Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
339d798a88 | ||
|
|
6580564767 | ||
|
|
d3a36b6103 | ||
|
|
868eaa5e3d | ||
|
|
5743ebc4f8 | ||
|
|
19ec020046 | ||
|
|
8353a24f6b | ||
|
|
670e6675cc | ||
|
|
cdd854bd70 | ||
|
|
cbb1f52467 | ||
|
|
62e2255b5e | ||
|
|
d7d270510f | ||
|
|
a5c297b911 | ||
|
|
0011c9d4e5 | ||
|
|
db0d2cf215 | ||
|
|
ec370a3c17 | ||
|
|
b0d751540e | ||
|
|
06237579f0 | ||
|
|
c038a54f2e | ||
|
|
b014734f33 | ||
|
|
fe98c13206 | ||
|
|
febcdc111e | ||
|
|
73d2c4c1ed | ||
|
|
fc12cecd30 | ||
|
|
803c205994 | ||
|
|
28b5b52a8f | ||
|
|
684481fd2c | ||
|
|
bf532ba35d | ||
|
|
0896dd46d1 | ||
|
|
e9ba9e2700 |
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
# DeepSeek AI API Key
|
||||||
|
# Get your API key from https://platform.deepseek.com/
|
||||||
|
DEEPSEEK_API_KEY=your_deepseek_api_key_here
|
||||||
Binary file not shown.
Binary file not shown.
Whitespace-only changes.
@@ -1,10 +1,11 @@
|
|||||||
|
const { pathsToModuleNameMapper } = require('ts-jest');
|
||||||
|
const { compilerOptions } = require('./tsconfig');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
preset: 'ts-jest',
|
preset: 'ts-jest',
|
||||||
testEnvironment: 'jsdom',
|
testEnvironment: 'jsdom',
|
||||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
||||||
moduleNameMapping: {
|
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
|
||||||
'^@/(.*)$': '<rootDir>/src/$1',
|
|
||||||
},
|
|
||||||
testMatch: [
|
testMatch: [
|
||||||
'**/__tests__/**/*.(ts|tsx|js)',
|
'**/__tests__/**/*.(ts|tsx|js)',
|
||||||
'**/*.(test|spec).(ts|tsx|js)',
|
'**/*.(test|spec).(ts|tsx|js)',
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
import '@testing-library/jest-dom'
|
require('@testing-library/jest-dom')
|
||||||
Generated
+1257
-9
File diff suppressed because it is too large.
Load diff
@@ -15,6 +15,7 @@
|
|||||||
"@fitai/database": "file:../../packages/database",
|
"@fitai/database": "file:../../packages/database",
|
||||||
"@fitai/shared": "file:../../packages/shared",
|
"@fitai/shared": "file:../../packages/shared",
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@tanstack/react-query": "^5.90.7",
|
"@tanstack/react-query": "^5.90.7",
|
||||||
"@types/bcryptjs": "^3.0.0",
|
"@types/bcryptjs": "^3.0.0",
|
||||||
@@ -26,10 +27,11 @@
|
|||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
"better-sqlite3": "^11.10.0",
|
"better-sqlite3": "12.4.1",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
"drizzle-orm": "^0.44.7",
|
"drizzle-orm": "^0.44.7",
|
||||||
"lucide-react": "^0.553.0",
|
"lucide-react": "^0.553.0",
|
||||||
"next": "^16.0.1",
|
"next": "^16.0.1",
|
||||||
@@ -49,12 +51,15 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
|
"@types/jest": "^30.0.0",
|
||||||
"@types/node": "^24.10.0",
|
"@types/node": "^24.10.0",
|
||||||
"@types/react": "19.2.2",
|
"@types/react": "19.2.2",
|
||||||
"@types/react-dom": "^19.2.2",
|
"@types/react-dom": "^19.2.2",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-config-next": "^16.0.1",
|
"eslint-config-next": "^16.0.1",
|
||||||
"jest": "^30.2.0",
|
"jest": "^30.2.0",
|
||||||
|
"jest-environment-jsdom": "^30.2.0",
|
||||||
|
"ts-jest": "^29.4.6",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
import { getDatabase } from '../src/lib/database';
|
||||||
|
import { DrizzleDatabase } from '../src/lib/database/drizzle';
|
||||||
|
|
||||||
|
async function checkUserRole() {
|
||||||
|
const db = await getDatabase();
|
||||||
|
const users = await db.getAllUsers();
|
||||||
|
console.log('Users found:', users.length);
|
||||||
|
users.forEach(u => {
|
||||||
|
console.log(`User: ${u.email}, Role: ${u.role}, ID: ${u.id}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkUserRole().catch(console.error);
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
const Database = require('better-sqlite3');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const dbPath = path.join(__dirname, '../data/fitai.db');
|
||||||
|
const db = new Database(dbPath);
|
||||||
|
|
||||||
|
console.log('Creating fitness_goals table...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS fitness_goals (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
fitness_profile_id TEXT,
|
||||||
|
goal_type TEXT NOT NULL CHECK(goal_type IN ('weight_target', 'strength_milestone', 'endurance_target', 'flexibility_goal', 'habit_building', 'custom')),
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
target_value REAL,
|
||||||
|
current_value REAL,
|
||||||
|
unit TEXT,
|
||||||
|
start_date INTEGER NOT NULL,
|
||||||
|
target_date INTEGER,
|
||||||
|
completed_date INTEGER,
|
||||||
|
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'completed', 'abandoned', 'paused')),
|
||||||
|
progress REAL DEFAULT 0,
|
||||||
|
priority TEXT DEFAULT 'medium' CHECK(priority IN ('low', 'medium', 'high')),
|
||||||
|
notes TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (fitness_profile_id) REFERENCES fitness_profiles(userId) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Create indexes for better query performance
|
||||||
|
db.exec(`
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_fitness_goals_user_id ON fitness_goals(user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_fitness_goals_status ON fitness_goals(status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_fitness_goals_profile_id ON fitness_goals(fitness_profile_id);
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log('✅ fitness_goals table created successfully');
|
||||||
|
console.log('✅ Indexes created successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Migration failed:', error);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
import { getDatabase } from '../src/lib/database';
|
||||||
|
|
||||||
|
async function makeAdmin(email: string) {
|
||||||
|
const db = await getDatabase();
|
||||||
|
const user = await db.getUserByEmail(email);
|
||||||
|
if (!user) {
|
||||||
|
console.log('User not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await db.updateUser(user.id, { role: 'admin' });
|
||||||
|
console.log(`User ${email} updated to admin`);
|
||||||
|
}
|
||||||
|
|
||||||
|
makeAdmin('taratur@gmail.com').catch(console.error);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
const Database = require('better-sqlite3');
|
const Database = require('better-sqlite3');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const dbPath = path.join(__dirname, '../../../data/fitai.db');
|
const dbPath = path.join(__dirname, '../data/fitai.db');
|
||||||
const db = new Database(dbPath);
|
const db = new Database(dbPath);
|
||||||
|
|
||||||
console.log('Migrating fitness_profiles table...');
|
console.log('Migrating fitness_profiles table...');
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
import 'dotenv/config';
|
||||||
|
import { getDatabase } from '../src/lib/database';
|
||||||
|
import { clerkClient } from '@clerk/nextjs/server';
|
||||||
|
|
||||||
|
async function syncAllUsers() {
|
||||||
|
console.log('Starting full user sync...');
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Fetch all users from Clerk
|
||||||
|
// Note: pagination might be needed for large user bases, but for prototype this is fine.
|
||||||
|
const client = await clerkClient();
|
||||||
|
const response = await client.users.getUserList({ limit: 100 });
|
||||||
|
const clerkUsers = response.data;
|
||||||
|
|
||||||
|
console.log(`Found ${clerkUsers.length} users in Clerk.`);
|
||||||
|
|
||||||
|
for (const clerkUser of clerkUsers) {
|
||||||
|
const userId = clerkUser.id;
|
||||||
|
const email = clerkUser.emailAddresses[0]?.emailAddress;
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
console.warn(`User ${userId} has no email, skipping.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingUser = await db.getUserById(userId);
|
||||||
|
if (existingUser) {
|
||||||
|
console.log(`User ${email} (${userId}) already exists.`);
|
||||||
|
// Optional: Update details if needed
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check by email to handle ID mismatches (e.g. from seeding)
|
||||||
|
const existingByEmail = await db.getUserByEmail(email);
|
||||||
|
if (existingByEmail) {
|
||||||
|
console.log(`User ${email} found with old ID ${existingByEmail.id}. Migrating to ${userId}...`);
|
||||||
|
await db.migrateUserId(existingByEmail.id, userId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Creating new user ${email} (${userId})...`);
|
||||||
|
await db.createUser({
|
||||||
|
id: userId,
|
||||||
|
email,
|
||||||
|
firstName: clerkUser.firstName || '',
|
||||||
|
lastName: clerkUser.lastName || '',
|
||||||
|
password: '', // Managed by Clerk
|
||||||
|
phone: clerkUser.phoneNumbers[0]?.phoneNumber || undefined,
|
||||||
|
role: (clerkUser.publicMetadata.role as 'admin' | 'client' | 'superAdmin') || 'client'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Sync complete.');
|
||||||
|
}
|
||||||
|
|
||||||
|
syncAllUsers().catch(console.error);
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"transpileOnly": true,
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
import { getDatabase } from '../src/lib/database/index';
|
||||||
|
|
||||||
|
async function verifyDatabase() {
|
||||||
|
console.log('Starting database verification...');
|
||||||
|
const db = await getDatabase();
|
||||||
|
await db.connect();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Create User
|
||||||
|
console.log('Creating test user...');
|
||||||
|
const userId = `test-user-${Date.now()}`;
|
||||||
|
const user = await db.createUser({
|
||||||
|
id: userId,
|
||||||
|
email: `test-${Date.now()}@example.com`,
|
||||||
|
firstName: 'Test',
|
||||||
|
lastName: 'User',
|
||||||
|
password: 'password123',
|
||||||
|
role: 'client',
|
||||||
|
phone: '1234567890'
|
||||||
|
});
|
||||||
|
console.log('User created:', user.id);
|
||||||
|
|
||||||
|
// 2. Create Client
|
||||||
|
console.log('Creating test client...');
|
||||||
|
const client = await db.createClient({
|
||||||
|
userId: user.id,
|
||||||
|
membershipType: 'basic',
|
||||||
|
membershipStatus: 'active',
|
||||||
|
joinDate: new Date()
|
||||||
|
});
|
||||||
|
console.log('Client created:', client.id);
|
||||||
|
|
||||||
|
// 3. Create Fitness Profile
|
||||||
|
console.log('Creating fitness profile...');
|
||||||
|
const profile = await db.createFitnessProfile({
|
||||||
|
id: 'test-profile-id',
|
||||||
|
userId: user.id,
|
||||||
|
height: '180',
|
||||||
|
weight: '75',
|
||||||
|
age: '30',
|
||||||
|
gender: 'male',
|
||||||
|
activityLevel: 'moderately_active',
|
||||||
|
fitnessGoals: ['weight_loss'],
|
||||||
|
exerciseHabits: 'None',
|
||||||
|
dietHabits: 'None',
|
||||||
|
medicalConditions: 'None'
|
||||||
|
});
|
||||||
|
console.log('Fitness profile created for:', profile.userId);
|
||||||
|
|
||||||
|
// 4. Attendance Check-in
|
||||||
|
console.log('Checking in...');
|
||||||
|
const checkIn = await db.checkIn(user.id, 'gym', 'Test check-in');
|
||||||
|
console.log('Checked in:', checkIn.id);
|
||||||
|
|
||||||
|
// 5. Verify Active Check-in
|
||||||
|
const activeCheckIn = await db.getActiveCheckIn(user.id);
|
||||||
|
if (!activeCheckIn || activeCheckIn.id !== checkIn.id) {
|
||||||
|
throw new Error('Active check-in verification failed');
|
||||||
|
}
|
||||||
|
console.log('Active check-in verified');
|
||||||
|
|
||||||
|
// 6. Attendance Check-out
|
||||||
|
console.log('Checking out...');
|
||||||
|
const checkOut = await db.checkOut(checkIn.id);
|
||||||
|
console.log('Checked out:', checkOut?.checkOutTime);
|
||||||
|
|
||||||
|
// 7. Cleanup
|
||||||
|
console.log('Cleaning up...');
|
||||||
|
await db.deleteUser(user.id);
|
||||||
|
console.log('Cleanup complete');
|
||||||
|
|
||||||
|
console.log('✅ Verification successful!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Verification failed:', error);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
await db.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyDatabase();
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { auth } from '@clerk/nextjs/server'
|
||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { getDatabase, DatabaseFactory } from '@/lib/database'
|
||||||
|
import { ensureUserSynced } from '@/lib/sync-user'
|
||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
const BACKUP_DIR = path.join(process.cwd(), 'backups')
|
||||||
|
const DB_PATH = path.join(process.cwd(), 'data', 'fitai.db')
|
||||||
|
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth()
|
||||||
|
if (!userId) return new NextResponse('Unauthorized', { status: 401 })
|
||||||
|
|
||||||
|
const db = await getDatabase()
|
||||||
|
const user = await ensureUserSynced(userId, db)
|
||||||
|
|
||||||
|
if (!user || (user.role !== 'admin' && user.role !== 'superAdmin')) {
|
||||||
|
return new NextResponse('Forbidden', { status: 403 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const { filename } = await req.json()
|
||||||
|
if (!filename) {
|
||||||
|
return new NextResponse('Filename is required', { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const backupPath = path.join(BACKUP_DIR, filename)
|
||||||
|
if (!fs.existsSync(backupPath)) {
|
||||||
|
return new NextResponse('Backup file not found', { status: 404 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close existing connection
|
||||||
|
await DatabaseFactory.disconnect()
|
||||||
|
|
||||||
|
// Restore file
|
||||||
|
fs.copyFileSync(backupPath, DB_PATH)
|
||||||
|
|
||||||
|
// Re-initialize connection (will happen automatically on next getDatabase call, but good to verify)
|
||||||
|
await getDatabase()
|
||||||
|
|
||||||
|
return NextResponse.json({ success: true })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Restore backup error:', error)
|
||||||
|
return new NextResponse('Internal Server Error', { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { auth } from '@clerk/nextjs/server'
|
||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { getDatabase } from '@/lib/database'
|
||||||
|
import { ensureUserSynced } from '@/lib/sync-user'
|
||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
const BACKUP_DIR = path.join(process.cwd(), 'backups')
|
||||||
|
const DB_PATH = path.join(process.cwd(), 'data', 'fitai.db')
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth()
|
||||||
|
if (!userId) return new NextResponse('Unauthorized', { status: 401 })
|
||||||
|
|
||||||
|
const db = await getDatabase()
|
||||||
|
const user = await ensureUserSynced(userId, db)
|
||||||
|
|
||||||
|
if (!user || (user.role !== 'admin' && user.role !== 'superAdmin')) {
|
||||||
|
return new NextResponse('Forbidden', { status: 403 })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(BACKUP_DIR)) {
|
||||||
|
fs.mkdirSync(BACKUP_DIR, { recursive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = fs.readdirSync(BACKUP_DIR)
|
||||||
|
.filter(file => file.endsWith('.db'))
|
||||||
|
.map(file => {
|
||||||
|
const stats = fs.statSync(path.join(BACKUP_DIR, file))
|
||||||
|
return {
|
||||||
|
name: file,
|
||||||
|
size: stats.size,
|
||||||
|
createdAt: stats.birthtime
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
||||||
|
|
||||||
|
return NextResponse.json(files)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('List backups error:', error)
|
||||||
|
return new NextResponse('Internal Server Error', { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function POST() {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth()
|
||||||
|
if (!userId) return new NextResponse('Unauthorized', { status: 401 })
|
||||||
|
|
||||||
|
const db = await getDatabase()
|
||||||
|
const user = await ensureUserSynced(userId, db)
|
||||||
|
|
||||||
|
if (!user || (user.role !== 'admin' && user.role !== 'superAdmin')) {
|
||||||
|
return new NextResponse('Forbidden', { status: 403 })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(BACKUP_DIR)) {
|
||||||
|
fs.mkdirSync(BACKUP_DIR, { recursive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
||||||
|
const backupPath = path.join(BACKUP_DIR, `backup-${timestamp}.db`)
|
||||||
|
|
||||||
|
// Ensure source DB exists
|
||||||
|
if (!fs.existsSync(DB_PATH)) {
|
||||||
|
return new NextResponse('Database file not found', { status: 404 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy file
|
||||||
|
fs.copyFileSync(DB_PATH, backupPath)
|
||||||
|
|
||||||
|
return NextResponse.json({ success: true, filename: `backup-${timestamp}.db` })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Create backup error:', error)
|
||||||
|
return new NextResponse('Internal Server Error', { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { auth } from "@clerk/nextjs/server";
|
||||||
|
import { getDatabase } from "@/lib/database";
|
||||||
|
import { ensureUserSynced } from "@/lib/sync-user";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/admin/clients
|
||||||
|
*
|
||||||
|
* Admin:
|
||||||
|
* - Lists clients scoped to the admin's gym (requires admin.gymId).
|
||||||
|
*
|
||||||
|
* SuperAdmin:
|
||||||
|
* - Optional query param ?gymId=<id> to filter clients by a specific gym.
|
||||||
|
* - If no gymId provided, returns all clients across all gyms.
|
||||||
|
*
|
||||||
|
* Response: Array of client users with minimal fields for listing, including membership data.
|
||||||
|
*/
|
||||||
|
export async function GET(req: Request) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDatabase();
|
||||||
|
const user = await ensureUserSynced(userId, db);
|
||||||
|
|
||||||
|
if (!user || (user.role !== "admin" && user.role !== "superAdmin")) {
|
||||||
|
return new NextResponse("Forbidden", { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = new URL(req.url);
|
||||||
|
const requestedGymId = url.searchParams.get("gymId");
|
||||||
|
|
||||||
|
// Admins must have a gymId; scope to their gym
|
||||||
|
let targetGymId: string | null = null;
|
||||||
|
if (user.role === "admin") {
|
||||||
|
if (!user.gymId) {
|
||||||
|
return new NextResponse("Admin gymId not set", { status: 400 });
|
||||||
|
}
|
||||||
|
targetGymId = user.gymId;
|
||||||
|
} else if (user.role === "superAdmin") {
|
||||||
|
targetGymId = requestedGymId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch users and clients
|
||||||
|
const allUsers = await db.getAllUsers();
|
||||||
|
const usersById = new Map(allUsers.map((u) => [u.id, u]));
|
||||||
|
const allClients = await db.getAllClients();
|
||||||
|
|
||||||
|
// Scope clients by gym when provided
|
||||||
|
const scopedClients = targetGymId
|
||||||
|
? allClients.filter((c) => {
|
||||||
|
const u = usersById.get(c.userId);
|
||||||
|
return u?.gymId === targetGymId;
|
||||||
|
})
|
||||||
|
: allClients;
|
||||||
|
|
||||||
|
// Compose payload merging user and client info
|
||||||
|
const payload = scopedClients.map((c) => {
|
||||||
|
const u = usersById.get(c.userId);
|
||||||
|
return {
|
||||||
|
id: c.id,
|
||||||
|
userId: c.userId,
|
||||||
|
email: u?.email ?? null,
|
||||||
|
firstName: u?.firstName ?? null,
|
||||||
|
lastName: u?.lastName ?? null,
|
||||||
|
gymId: u?.gymId ?? null,
|
||||||
|
membershipType: c.membershipType,
|
||||||
|
membershipStatus: c.membershipStatus,
|
||||||
|
joinDate: c.joinDate,
|
||||||
|
lastVisit: c.lastVisit ?? null,
|
||||||
|
emergencyContact: c.emergencyContact ?? null,
|
||||||
|
createdAt: u?.createdAt ?? null,
|
||||||
|
updatedAt: u?.updatedAt ?? null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(payload);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("GET /api/admin/clients error:", error);
|
||||||
|
return new NextResponse("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { auth, clerkClient } from "@clerk/nextjs/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/admin/set-user-metadata
|
||||||
|
*
|
||||||
|
* Sets Clerk publicMetadata.role and publicMetadata.gymId for a target user.
|
||||||
|
*
|
||||||
|
* Authorization:
|
||||||
|
* - Caller must be an admin or superAdmin (based on their Clerk publicMetadata.role).
|
||||||
|
*
|
||||||
|
* Request body:
|
||||||
|
* {
|
||||||
|
* "targetUserId": string, // Clerk user ID of the target
|
||||||
|
* "role": "superAdmin" | "admin" | "trainer" | "client" | "generalUser", // optional
|
||||||
|
* "gymId": string | null // optional; null clears gym assignment
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Behavior:
|
||||||
|
* - If "role" is provided, update the target user's publicMetadata.role.
|
||||||
|
* - If "gymId" is provided (including null), update publicMetadata.gymId.
|
||||||
|
* - Validates inputs and permissions.
|
||||||
|
*
|
||||||
|
* Response:
|
||||||
|
* - 200 with updated minimal user data
|
||||||
|
* - 400/401/403/404/500 on errors
|
||||||
|
*/
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
// Authenticate the requester
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = await clerkClient();
|
||||||
|
|
||||||
|
// Fetch requester from Clerk to verify permissions
|
||||||
|
const requester = await client.users.getUser(userId);
|
||||||
|
const requesterRole =
|
||||||
|
(requester.publicMetadata?.role as
|
||||||
|
| "superAdmin"
|
||||||
|
| "admin"
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "generalUser") ?? "client";
|
||||||
|
|
||||||
|
// Only admin or superAdmin can set metadata
|
||||||
|
if (requesterRole !== "admin" && requesterRole !== "superAdmin") {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Forbidden: admin or superAdmin access required" },
|
||||||
|
{ status: 403 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse body
|
||||||
|
const body = await req.json().catch(() => null);
|
||||||
|
if (!body || typeof body !== "object") {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Invalid JSON body" },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetUserId = typeof body.targetUserId === "string" ? body.targetUserId : null;
|
||||||
|
const role = body.role as
|
||||||
|
| "superAdmin"
|
||||||
|
| "admin"
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "generalUser"
|
||||||
|
| undefined;
|
||||||
|
const gymId =
|
||||||
|
body.gymId === null
|
||||||
|
? null
|
||||||
|
: typeof body.gymId === "string"
|
||||||
|
? body.gymId
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!targetUserId) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Invalid or missing targetUserId" },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate role if provided
|
||||||
|
const allowedRoles = ["superAdmin", "admin", "trainer", "client", "generalUser"] as const;
|
||||||
|
if (role && !allowedRoles.includes(role)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Invalid role. Must be one of superAdmin, admin, trainer, client, generalUser" },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent non-superAdmin from assigning superAdmin
|
||||||
|
if (role === "superAdmin" && requesterRole !== "superAdmin") {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Only superAdmin can assign superAdmin role" },
|
||||||
|
{ status: 403 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch target user to ensure they exist
|
||||||
|
let targetUser;
|
||||||
|
try {
|
||||||
|
targetUser = await client.users.getUser(targetUserId);
|
||||||
|
} catch {
|
||||||
|
return NextResponse.json({ error: "Target user not found" }, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct new metadata by merging with existing
|
||||||
|
const newPublicMetadata: Record<string, unknown> = {
|
||||||
|
...(targetUser.publicMetadata || {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (role !== undefined) {
|
||||||
|
newPublicMetadata.role = role;
|
||||||
|
}
|
||||||
|
if (gymId !== undefined) {
|
||||||
|
newPublicMetadata.gymId = gymId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure at least one field to update
|
||||||
|
if (role === undefined && gymId === undefined) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Provide at least one of 'role' or 'gymId' to update" },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform update on Clerk
|
||||||
|
const updatedUser = await client.users.updateUser(targetUserId, {
|
||||||
|
publicMetadata: newPublicMetadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Construct response payload
|
||||||
|
const primaryEmail =
|
||||||
|
updatedUser.emailAddresses?.find(
|
||||||
|
(e) => e.id === updatedUser.primaryEmailAddressId
|
||||||
|
)?.emailAddress || updatedUser.emailAddresses?.[0]?.emailAddress || null;
|
||||||
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
message: "User metadata updated",
|
||||||
|
user: {
|
||||||
|
id: updatedUser.id,
|
||||||
|
email: primaryEmail,
|
||||||
|
firstName: updatedUser.firstName,
|
||||||
|
lastName: updatedUser.lastName,
|
||||||
|
role: updatedUser.publicMetadata?.role ?? null,
|
||||||
|
gymId: updatedUser.publicMetadata?.gymId ?? null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ status: 200 }
|
||||||
|
);
|
||||||
|
} catch (error: any) {
|
||||||
|
const message =
|
||||||
|
error?.errors?.[0]?.message ||
|
||||||
|
error?.message ||
|
||||||
|
"Internal server error";
|
||||||
|
console.error("Error setting user metadata:", error);
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,59 @@
|
|||||||
import { auth } from '@clerk/nextjs/server'
|
import { auth } from "@clerk/nextjs/server";
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from "next/server";
|
||||||
import { getDatabase } from '@/lib/database'
|
import { getDatabase } from "@/lib/database";
|
||||||
import { ensureUserSynced } from '@/lib/sync-user'
|
import { ensureUserSynced } from "@/lib/sync-user";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET(req: Request) {
|
||||||
try {
|
try {
|
||||||
const { userId } = await auth()
|
const { userId } = await auth();
|
||||||
if (!userId) return new NextResponse('Unauthorized', { status: 401 })
|
if (!userId) return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
|
||||||
const db = await getDatabase()
|
const db = await getDatabase();
|
||||||
const user = await ensureUserSynced(userId, db)
|
const user = await ensureUserSynced(userId, db);
|
||||||
|
|
||||||
if (!user || (user.role !== 'admin' && user.role !== 'superAdmin')) {
|
if (!user || (user.role !== "admin" && user.role !== "superAdmin")) {
|
||||||
return new NextResponse('Forbidden', { status: 403 })
|
return new NextResponse("Forbidden", { status: 403 });
|
||||||
|
}
|
||||||
|
if (user.role === "admin" && !user.gymId) {
|
||||||
|
return new NextResponse("Admin gymId not set", { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const stats = await db.getDashboardStats()
|
const url = new URL(req.url);
|
||||||
|
const searchParams = url.searchParams;
|
||||||
|
|
||||||
return NextResponse.json(stats)
|
let targetGymId: string | null = null;
|
||||||
|
if (user.role === "admin") {
|
||||||
|
targetGymId = user.gymId ?? null;
|
||||||
|
} else if (user.role === "superAdmin") {
|
||||||
|
targetGymId = searchParams.get("gymId");
|
||||||
|
}
|
||||||
|
|
||||||
|
const allUsers = await db.getAllUsers();
|
||||||
|
const allClients = await db.getAllClients();
|
||||||
|
|
||||||
|
const usersById = new Map(allUsers.map((u) => [u.id, u]));
|
||||||
|
const filteredUsers = targetGymId
|
||||||
|
? allUsers.filter((u) => u.gymId === targetGymId)
|
||||||
|
: allUsers;
|
||||||
|
const filteredClients = targetGymId
|
||||||
|
? allClients.filter((c) => {
|
||||||
|
const u = usersById.get(c.userId);
|
||||||
|
return u?.gymId === targetGymId;
|
||||||
|
})
|
||||||
|
: allClients;
|
||||||
|
|
||||||
|
const stats = {
|
||||||
|
totalUsers: filteredUsers.length,
|
||||||
|
activeClients: filteredClients.filter(
|
||||||
|
(c) => c.membershipStatus === "active",
|
||||||
|
).length,
|
||||||
|
totalRevenue: 0,
|
||||||
|
revenueGrowth: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return NextResponse.json(stats);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Dashboard stats error:', error)
|
console.error("Dashboard stats error:", error);
|
||||||
return new NextResponse('Internal Server Error', { status: 500 })
|
return new NextResponse("Internal Server Error", { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { auth } from "@clerk/nextjs/server";
|
||||||
|
import { getDatabase } from "@/lib/database";
|
||||||
|
import { ensureUserSynced } from "@/lib/sync-user";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/admin/trainers
|
||||||
|
*
|
||||||
|
* Admin:
|
||||||
|
* - Lists trainers scoped to the admin's gym (requires admin.gymId).
|
||||||
|
*
|
||||||
|
* SuperAdmin:
|
||||||
|
* - Optional query param ?gymId=<id> to filter trainers by a specific gym.
|
||||||
|
* - If no gymId provided, returns all trainers across all gyms.
|
||||||
|
*
|
||||||
|
* Response: Array of trainer users with minimal fields for listing
|
||||||
|
*/
|
||||||
|
export async function GET(req: Request) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDatabase();
|
||||||
|
const user = await ensureUserSynced(userId, db);
|
||||||
|
|
||||||
|
if (!user || (user.role !== "admin" && user.role !== "superAdmin")) {
|
||||||
|
return new NextResponse("Forbidden", { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = new URL(req.url);
|
||||||
|
const requestedGymId = url.searchParams.get("gymId");
|
||||||
|
|
||||||
|
// Admins must have a gymId; scope to their gym
|
||||||
|
let targetGymId: string | null = null;
|
||||||
|
if (user.role === "admin") {
|
||||||
|
if (!user.gymId) {
|
||||||
|
return new NextResponse("Admin gymId not set", { status: 400 });
|
||||||
|
}
|
||||||
|
targetGymId = user.gymId as string;
|
||||||
|
} else if (user.role === "superAdmin") {
|
||||||
|
targetGymId = requestedGymId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all users and filter to trainers
|
||||||
|
const allUsers = await db.getAllUsers();
|
||||||
|
let trainers = allUsers.filter((u) => u.role === "trainer");
|
||||||
|
|
||||||
|
// Scope by gym when required/provided
|
||||||
|
if (targetGymId) {
|
||||||
|
trainers = trainers.filter((t) => t.gymId === targetGymId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimal payload suitable for listing
|
||||||
|
const payload = trainers.map((t) => ({
|
||||||
|
id: t.id,
|
||||||
|
email: t.email,
|
||||||
|
firstName: t.firstName,
|
||||||
|
lastName: t.lastName,
|
||||||
|
gymId: t.gymId ?? null,
|
||||||
|
createdAt: t.createdAt,
|
||||||
|
updatedAt: t.updatedAt,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return NextResponse.json(payload);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("GET /api/admin/trainers error:", error);
|
||||||
|
return new NextResponse("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
/**
|
||||||
|
* @jest-environment node
|
||||||
|
*/
|
||||||
|
import { POST as checkIn } from '../check-in/route'
|
||||||
|
import { POST as checkOut } from '../check-out/route'
|
||||||
|
import { GET as history } from '../history/route'
|
||||||
|
import { NextRequest } from 'next/server'
|
||||||
|
|
||||||
|
// Mock dependencies
|
||||||
|
jest.mock('@clerk/nextjs/server', () => ({
|
||||||
|
auth: jest.fn(() => Promise.resolve({ userId: 'test_user_id' })),
|
||||||
|
currentUser: jest.fn(() => Promise.resolve({ id: 'test_user_id', emailAddresses: [{ emailAddress: 'test@example.com' }] }))
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('@/lib/sync-user', () => ({
|
||||||
|
ensureUserSynced: jest.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mockDb = {
|
||||||
|
checkIn: jest.fn(),
|
||||||
|
checkOut: jest.fn(),
|
||||||
|
getAttendanceHistory: jest.fn(),
|
||||||
|
getActiveCheckIn: jest.fn(),
|
||||||
|
getUserById: jest.fn(),
|
||||||
|
createUser: jest.fn(),
|
||||||
|
getClientByUserId: jest.fn(),
|
||||||
|
createClient: jest.fn(),
|
||||||
|
getFitnessProfileByUserId: jest.fn(),
|
||||||
|
createFitnessProfile: jest.fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.mock('@/lib/database', () => ({
|
||||||
|
getDatabase: jest.fn(() => Promise.resolve(mockDb))
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('Attendance API', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('POST /api/attendance/check-in', () => {
|
||||||
|
it('should successfully check in', async () => {
|
||||||
|
mockDb.getUserById.mockResolvedValue({ id: 'test_user_id' })
|
||||||
|
mockDb.getActiveCheckIn.mockResolvedValue(null)
|
||||||
|
mockDb.checkIn.mockResolvedValue({
|
||||||
|
id: 'attendance_id',
|
||||||
|
userId: 'test_user_id',
|
||||||
|
checkInTime: new Date(),
|
||||||
|
type: 'gym'
|
||||||
|
})
|
||||||
|
|
||||||
|
const req = new NextRequest('http://localhost/api/attendance/check-in', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ type: 'gym', notes: 'Test check-in' })
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await checkIn(req)
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(data.id).toBe('attendance_id')
|
||||||
|
expect(data.userId).toBe('test_user_id')
|
||||||
|
expect(mockDb.checkIn).toHaveBeenCalledWith('test_user_id', 'gym', 'Test check-in')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail if already checked in', async () => {
|
||||||
|
mockDb.getUserById.mockResolvedValue({ id: 'test_user_id' })
|
||||||
|
mockDb.getActiveCheckIn.mockResolvedValue({ id: 'existing_id' })
|
||||||
|
|
||||||
|
const req = new NextRequest('http://localhost/api/attendance/check-in', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ type: 'gym' })
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await checkIn(req)
|
||||||
|
const text = await res.text()
|
||||||
|
|
||||||
|
expect(res.status).toBe(400)
|
||||||
|
expect(text).toBe('Already checked in')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('POST /api/attendance/check-out', () => {
|
||||||
|
it('should successfully check out', async () => {
|
||||||
|
mockDb.getActiveCheckIn.mockResolvedValue({ id: 'attendance_id' })
|
||||||
|
mockDb.checkOut.mockResolvedValue({
|
||||||
|
id: 'attendance_id',
|
||||||
|
checkOutTime: new Date()
|
||||||
|
})
|
||||||
|
|
||||||
|
const req = new NextRequest('http://localhost/api/attendance/check-out', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await checkOut(req)
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(data.id).toBe('attendance_id')
|
||||||
|
expect(data.checkOutTime).toBeDefined()
|
||||||
|
expect(mockDb.checkOut).toHaveBeenCalledWith('attendance_id')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail if not checked in', async () => {
|
||||||
|
mockDb.getActiveCheckIn.mockResolvedValue(null)
|
||||||
|
|
||||||
|
const req = new NextRequest('http://localhost/api/attendance/check-out', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await checkOut(req)
|
||||||
|
const text = await res.text()
|
||||||
|
|
||||||
|
expect(res.status).toBe(404)
|
||||||
|
expect(text).toBe('No active check-in found')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('GET /api/attendance/history', () => {
|
||||||
|
it('should return attendance history', async () => {
|
||||||
|
const historyData = [
|
||||||
|
{ id: '1', checkInTime: new Date() },
|
||||||
|
{ id: '2', checkInTime: new Date() }
|
||||||
|
]
|
||||||
|
mockDb.getUserById.mockResolvedValue({ id: 'test_user_id' })
|
||||||
|
mockDb.getAttendanceHistory.mockResolvedValue(historyData)
|
||||||
|
|
||||||
|
const req = new NextRequest('http://localhost/api/attendance/history')
|
||||||
|
const res = await history(req)
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(data).toEqual(JSON.parse(JSON.stringify(historyData))) // Handle date serialization
|
||||||
|
expect(mockDb.getAttendanceHistory).toHaveBeenCalledWith('test_user_id')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -13,21 +13,8 @@ export async function POST(req: Request) {
|
|||||||
// Ensure user exists in DB (sync from Clerk if needed)
|
// Ensure user exists in DB (sync from Clerk if needed)
|
||||||
await ensureUserSynced(userId, db)
|
await ensureUserSynced(userId, db)
|
||||||
|
|
||||||
let client = await db.getClientByUserId(userId)
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
// Auto-create client profile if it doesn't exist
|
|
||||||
console.log('Client profile not found, creating new one for user:', userId)
|
|
||||||
client = await db.createClient({
|
|
||||||
userId,
|
|
||||||
membershipType: 'basic',
|
|
||||||
membershipStatus: 'active',
|
|
||||||
joinDate: new Date()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if already checked in
|
// Check if already checked in
|
||||||
const activeCheckIn = await db.getActiveCheckIn(client.id)
|
const activeCheckIn = await db.getActiveCheckIn(userId)
|
||||||
if (activeCheckIn) {
|
if (activeCheckIn) {
|
||||||
return new NextResponse('Already checked in', { status: 400 })
|
return new NextResponse('Already checked in', { status: 400 })
|
||||||
}
|
}
|
||||||
@@ -35,7 +22,7 @@ export async function POST(req: Request) {
|
|||||||
const body = await req.json()
|
const body = await req.json()
|
||||||
const { type = 'gym', notes } = body
|
const { type = 'gym', notes } = body
|
||||||
|
|
||||||
const attendance = await db.checkIn(client.id, type, notes)
|
const attendance = await db.checkIn(userId, type, notes)
|
||||||
return NextResponse.json(attendance)
|
return NextResponse.json(attendance)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Check-in error:', error)
|
console.error('Check-in error:', error)
|
||||||
|
|||||||
@@ -8,13 +8,8 @@ export async function POST(req: Request) {
|
|||||||
if (!userId) return new NextResponse('Unauthorized', { status: 401 })
|
if (!userId) return new NextResponse('Unauthorized', { status: 401 })
|
||||||
|
|
||||||
const db = await getDatabase()
|
const db = await getDatabase()
|
||||||
const client = await db.getClientByUserId(userId)
|
|
||||||
|
|
||||||
if (!client) {
|
const activeCheckIn = await db.getActiveCheckIn(userId)
|
||||||
return new NextResponse('Client profile not found', { status: 404 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeCheckIn = await db.getActiveCheckIn(client.id)
|
|
||||||
if (!activeCheckIn) {
|
if (!activeCheckIn) {
|
||||||
return new NextResponse('No active check-in found', { status: 404 })
|
return new NextResponse('No active check-in found', { status: 404 })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,20 +22,7 @@ export async function GET(req: Request) {
|
|||||||
// Ensure user exists in DB (sync from Clerk if needed)
|
// Ensure user exists in DB (sync from Clerk if needed)
|
||||||
await ensureUserSynced(userId, db)
|
await ensureUserSynced(userId, db)
|
||||||
|
|
||||||
let client = await db.getClientByUserId(userId)
|
const history = await db.getAttendanceHistory(userId)
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
// Auto-create client profile if it doesn't exist
|
|
||||||
console.log('Client profile not found, creating new one for user:', userId)
|
|
||||||
client = await db.createClient({
|
|
||||||
userId,
|
|
||||||
membershipType: 'basic',
|
|
||||||
membershipStatus: 'active',
|
|
||||||
joinDate: new Date()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const history = await db.getAttendanceHistory(client.id)
|
|
||||||
return NextResponse.json(history)
|
return NextResponse.json(history)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('History error:', error)
|
console.error('History error:', error)
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
import { auth } from '@clerk/nextjs/server';
|
||||||
|
import { getDatabase } from '@/lib/database';
|
||||||
|
|
||||||
|
// POST - Mark goal as complete
|
||||||
|
export async function POST(
|
||||||
|
req: NextRequest,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = await params;
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Verify goal exists and user owns it
|
||||||
|
const existingGoal = await db.getFitnessGoalById(id);
|
||||||
|
if (!existingGoal) {
|
||||||
|
return NextResponse.json({ error: 'Goal not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
if (existingGoal.userId !== userId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as completed
|
||||||
|
const completedGoal = await db.completeGoal(id);
|
||||||
|
|
||||||
|
return NextResponse.json(completedGoal);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error completing fitness goal:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Internal server error' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
import { auth } from '@clerk/nextjs/server';
|
||||||
|
import { getDatabase } from '@/lib/database';
|
||||||
|
|
||||||
|
// GET - Get specific goal
|
||||||
|
export async function GET(
|
||||||
|
req: NextRequest,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = await params;
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
const goal = await db.getFitnessGoalById(id);
|
||||||
|
|
||||||
|
if (!goal) {
|
||||||
|
return NextResponse.json({ error: 'Goal not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify ownership
|
||||||
|
if (goal.userId !== userId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json(goal);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching fitness goal:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Internal server error' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT - Update goal
|
||||||
|
export async function PUT(
|
||||||
|
req: NextRequest,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = await params;
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Verify goal exists and user owns it
|
||||||
|
const existingGoal = await db.getFitnessGoalById(id);
|
||||||
|
if (!existingGoal) {
|
||||||
|
return NextResponse.json({ error: 'Goal not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
if (existingGoal.userId !== userId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const updates = await req.json();
|
||||||
|
|
||||||
|
// Don't allow changing userId or id
|
||||||
|
delete updates.userId;
|
||||||
|
delete updates.id;
|
||||||
|
delete updates.createdAt;
|
||||||
|
|
||||||
|
const updatedGoal = await db.updateFitnessGoal(id, updates);
|
||||||
|
|
||||||
|
return NextResponse.json(updatedGoal);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating fitness goal:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Internal server error' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE - Delete goal
|
||||||
|
export async function DELETE(
|
||||||
|
req: NextRequest,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = await params;
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Verify goal exists and user owns it
|
||||||
|
const existingGoal = await db.getFitnessGoalById(id);
|
||||||
|
if (!existingGoal) {
|
||||||
|
return NextResponse.json({ error: 'Goal not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
if (existingGoal.userId !== userId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleted = await db.deleteFitnessGoal(id);
|
||||||
|
|
||||||
|
if (deleted) {
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
|
} else {
|
||||||
|
return NextResponse.json({ error: 'Failed to delete goal' }, { status: 500 });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting fitness goal:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Internal server error' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
import { auth } from '@clerk/nextjs/server';
|
||||||
|
import { getDatabase } from '@/lib/database';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
|
|
||||||
|
// GET - List user's fitness goals
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { searchParams } = new URL(req.url);
|
||||||
|
const targetUserId = searchParams.get('userId') || userId;
|
||||||
|
const status = searchParams.get('status'); // active, completed, all
|
||||||
|
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Fetch goals with optional status filter
|
||||||
|
const goals = await db.getFitnessGoalsByUserId(
|
||||||
|
targetUserId,
|
||||||
|
status && status !== 'all' ? status : undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
return NextResponse.json(goals);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching fitness goals:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Internal server error' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST - Create new fitness goal
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await req.json();
|
||||||
|
const {
|
||||||
|
goalType,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
targetValue,
|
||||||
|
currentValue,
|
||||||
|
unit,
|
||||||
|
targetDate,
|
||||||
|
priority,
|
||||||
|
notes,
|
||||||
|
fitnessProfileId
|
||||||
|
} = body;
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
if (!goalType || !title) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'goalType and title are required' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Create the goal
|
||||||
|
const goal = await db.createFitnessGoal({
|
||||||
|
id: randomBytes(16).toString('hex'),
|
||||||
|
userId,
|
||||||
|
fitnessProfileId: fitnessProfileId || undefined,
|
||||||
|
goalType,
|
||||||
|
title,
|
||||||
|
description: description || undefined,
|
||||||
|
targetValue: targetValue || undefined,
|
||||||
|
currentValue: currentValue || 0,
|
||||||
|
unit: unit || undefined,
|
||||||
|
startDate: new Date(),
|
||||||
|
targetDate: targetDate ? new Date(targetDate) : undefined,
|
||||||
|
status: 'active',
|
||||||
|
progress: 0,
|
||||||
|
priority: priority || 'medium',
|
||||||
|
notes: notes || undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(goal, { status: 201 });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating fitness goal:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Internal server error' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { auth } from "@clerk/nextjs/server";
|
||||||
|
import { eq, sql } from "@fitai/database";
|
||||||
|
import { db, users as usersTable } from "@fitai/database";
|
||||||
|
import { ensureUserSynced } from "@/lib/sync-user";
|
||||||
|
|
||||||
|
async function ensureGymsTable() {
|
||||||
|
await db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS gyms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
location TEXT,
|
||||||
|
status TEXT NOT NULL CHECK (status IN ('active','inactive')) DEFAULT 'active',
|
||||||
|
admin_user_id TEXT NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/gyms
|
||||||
|
// Lists active gyms for selection (grid)
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
await ensureGymsTable();
|
||||||
|
const rows = await db.all(
|
||||||
|
sql`SELECT * FROM gyms WHERE status = 'active' ORDER BY created_at DESC`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return NextResponse.json(rows);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("GET /gyms error:", error);
|
||||||
|
return new NextResponse("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/gyms
|
||||||
|
// Create a gym. Allowed roles: superAdmin, admin.
|
||||||
|
// - admin: can only create gyms for themselves (adminUserId = current user)
|
||||||
|
// - superAdmin: can create for self or specify adminUserId
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
await ensureGymsTable();
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
|
||||||
|
// Ensure our local DB has the user synced (role, etc.)
|
||||||
|
const currentUser = await ensureUserSynced(userId, {
|
||||||
|
// minimal facade for ensureUserSynced to work: it expects an object implementing part of IDatabase
|
||||||
|
getUserById: async (id: string) => {
|
||||||
|
const row = await db
|
||||||
|
.select()
|
||||||
|
.from(usersTable)
|
||||||
|
.where(eq(usersTable.id, id))
|
||||||
|
.get();
|
||||||
|
return row
|
||||||
|
? {
|
||||||
|
id: row.id,
|
||||||
|
email: row.email,
|
||||||
|
firstName: row.firstName,
|
||||||
|
lastName: row.lastName,
|
||||||
|
password: row.password ?? "",
|
||||||
|
phone: row.phone ?? undefined,
|
||||||
|
role: row.role,
|
||||||
|
imageUrl: undefined,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
updatedAt: new Date(row.updatedAt),
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
updateUser: async (id: string, updates: any) => {
|
||||||
|
await db
|
||||||
|
.update(usersTable)
|
||||||
|
.set({
|
||||||
|
...updates,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
})
|
||||||
|
.where(eq(usersTable.id, id))
|
||||||
|
.run();
|
||||||
|
const row = await db
|
||||||
|
.select()
|
||||||
|
.from(usersTable)
|
||||||
|
.where(eq(usersTable.id, id))
|
||||||
|
.get();
|
||||||
|
return row
|
||||||
|
? {
|
||||||
|
id: row.id,
|
||||||
|
email: row.email,
|
||||||
|
firstName: row.firstName,
|
||||||
|
lastName: row.lastName,
|
||||||
|
password: row.password ?? "",
|
||||||
|
phone: row.phone ?? undefined,
|
||||||
|
role: row.role,
|
||||||
|
imageUrl: undefined,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
updatedAt: new Date(row.updatedAt),
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!currentUser ||
|
||||||
|
(currentUser.role !== "admin" && currentUser.role !== "superAdmin")
|
||||||
|
) {
|
||||||
|
return new NextResponse("Forbidden", { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await req.json().catch(() => null);
|
||||||
|
if (!body || typeof body !== "object") {
|
||||||
|
return new NextResponse("Invalid JSON body", { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = String(body.name ?? "").trim();
|
||||||
|
const location = body.location ? String(body.location).trim() : null;
|
||||||
|
let adminUserId: string | null = body.adminUserId
|
||||||
|
? String(body.adminUserId)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
return NextResponse.json({ error: "name is required" }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce admin ownership rules
|
||||||
|
if (currentUser.role === "admin") {
|
||||||
|
adminUserId = currentUser.id;
|
||||||
|
} else if (currentUser.role === "superAdmin") {
|
||||||
|
adminUserId = adminUserId || currentUser.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic check that adminUserId exists and is an admin or superAdmin
|
||||||
|
const adminRow = await db
|
||||||
|
.select()
|
||||||
|
.from(usersTable)
|
||||||
|
.where(eq(usersTable.id, adminUserId!))
|
||||||
|
.get();
|
||||||
|
if (
|
||||||
|
!adminRow ||
|
||||||
|
(adminRow.role !== "admin" && adminRow.role !== "superAdmin")
|
||||||
|
) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "adminUserId must reference an admin or superAdmin" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = generateId();
|
||||||
|
const nowTs = Date.now();
|
||||||
|
|
||||||
|
await db.run(
|
||||||
|
sql`INSERT INTO gyms (id, name, location, status, admin_user_id, created_at, updated_at)
|
||||||
|
VALUES (${id}, ${name}, ${location ?? null}, 'active', ${adminUserId!}, ${nowTs}, ${nowTs})`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assign the admin to this gym immediately after creation
|
||||||
|
await db.run(
|
||||||
|
sql`UPDATE users SET gym_id = ${id}, updated_at = ${nowTs} WHERE id = ${adminUserId!}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const created = await db.get(sql`SELECT * FROM gyms WHERE id = ${id}`);
|
||||||
|
return NextResponse.json(created, { status: 201 });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("POST /gyms error:", error);
|
||||||
|
return new NextResponse("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateId(): string {
|
||||||
|
// Simple URL-safe id generator
|
||||||
|
return (
|
||||||
|
Math.random().toString(36).slice(2, 10) +
|
||||||
|
Math.random().toString(36).slice(2, 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { auth, clerkClient } from "@clerk/nextjs/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/invitations
|
||||||
|
*
|
||||||
|
* Create a Clerk-managed invitation and store role/gym context in publicMetadata.
|
||||||
|
* This endpoint does not implement invitation acceptance; Clerk’s acceptance link flow and webhooks will handle that.
|
||||||
|
*
|
||||||
|
* Body: {
|
||||||
|
* inviteeEmail: string,
|
||||||
|
* roleAssigned: 'trainer' | 'client' | 'admin'
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Rules:
|
||||||
|
* - admin: can invite trainer or client; the gymId is taken from inviter's publicMetadata or user record.
|
||||||
|
* - trainer: can invite client; the gymId is taken from inviter's publicMetadata or user record.
|
||||||
|
* - superAdmin: can invite admin; requires `gymId` in body, or falls back to inviter's `gymId` if present.
|
||||||
|
*
|
||||||
|
* Returns Clerk invitation payload.
|
||||||
|
*/
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
if (!userId) {
|
||||||
|
return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await req.json().catch(() => null);
|
||||||
|
if (!body || typeof body !== "object") {
|
||||||
|
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const inviteeEmail = String(body.inviteeEmail ?? "")
|
||||||
|
.trim()
|
||||||
|
.toLowerCase();
|
||||||
|
const roleAssigned = String(body.roleAssigned ?? "").trim() as
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "admin";
|
||||||
|
let requestedGymId: string | null = body.gymId ? String(body.gymId) : null;
|
||||||
|
|
||||||
|
if (!inviteeEmail || !roleAssigned) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "inviteeEmail and roleAssigned are required" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch inviter user from Clerk
|
||||||
|
const client = await clerkClient();
|
||||||
|
const inviter = await client.users.getUser(userId);
|
||||||
|
const inviterRole =
|
||||||
|
(inviter.publicMetadata?.role as
|
||||||
|
| "superAdmin"
|
||||||
|
| "admin"
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "generalUser") ?? "client";
|
||||||
|
const inviterGymId =
|
||||||
|
(inviter.publicMetadata?.gymId as string | undefined) ?? undefined;
|
||||||
|
|
||||||
|
// Enforce role-based rules and resolve target gymId for the invitation
|
||||||
|
let gymIdForInvite: string | null = null;
|
||||||
|
switch (inviterRole) {
|
||||||
|
case "admin": {
|
||||||
|
if (roleAssigned !== "trainer" && roleAssigned !== "client") {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Admin can only invite trainer or client" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!inviterGymId) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Inviter admin must be assigned to a gym" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
gymIdForInvite = inviterGymId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "trainer": {
|
||||||
|
if (roleAssigned !== "client") {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Trainer can only invite client" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!inviterGymId) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Inviter trainer must be assigned to a gym" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
gymIdForInvite = inviterGymId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "superAdmin": {
|
||||||
|
if (
|
||||||
|
roleAssigned !== "admin" &&
|
||||||
|
roleAssigned !== "trainer" &&
|
||||||
|
roleAssigned !== "client"
|
||||||
|
) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Invalid roleAssigned for SuperAdmin" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Prefer explicitly provided gymId, otherwise fall back to inviter's gymId if present
|
||||||
|
gymIdForInvite = requestedGymId || inviterGymId || null;
|
||||||
|
if (!gymIdForInvite) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "gymId is required for SuperAdmin when inviting" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Inviter role not permitted to create invitations" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Clerk invitation with metadata needed by webhook to assign role & gym
|
||||||
|
// reuse existing Clerk client instance
|
||||||
|
const invitation = await client.invitations.createInvitation({
|
||||||
|
emailAddress: inviteeEmail,
|
||||||
|
publicMetadata: {
|
||||||
|
roleAssigned,
|
||||||
|
gymId: gymIdForInvite,
|
||||||
|
inviterUserId: inviter.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(invitation, { status: 201 });
|
||||||
|
} catch (error: any) {
|
||||||
|
// Surface Clerk errors where possible
|
||||||
|
const message =
|
||||||
|
error?.errors?.[0]?.message ||
|
||||||
|
error?.message ||
|
||||||
|
"Failed to create invitation";
|
||||||
|
console.error("POST /api/invitations error:", error);
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { getDatabase } from "@/lib/database";
|
import { getDatabase } from "@/lib/database";
|
||||||
|
import { buildAIContext } from "@/lib/ai/ai-context";
|
||||||
|
import { buildEnhancedPrompt, buildBasicPrompt } from "@/lib/ai/prompt-builder";
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
try {
|
try {
|
||||||
const { userId } = await req.json();
|
const { userId, useExternalModel } = await req.json();
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return NextResponse.json({ error: "User ID is required" }, { status: 400 });
|
return NextResponse.json({ error: "User ID is required" }, { status: 400 });
|
||||||
@@ -21,35 +23,106 @@ export async function POST(req: Request) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct prompt for Ollama
|
// Build AI context with goals and recommendations
|
||||||
const prompt = `
|
let prompt: string;
|
||||||
You are a professional fitness trainer and nutritionist.
|
try {
|
||||||
Generate a detailed daily recommendation for a user with the following profile:
|
const context = await buildAIContext(userId);
|
||||||
- Height: ${profile.height} cm
|
prompt = buildEnhancedPrompt(context);
|
||||||
- Weight: ${profile.weight} kg
|
console.log('Using enhanced AI context with goals and history');
|
||||||
- Age: ${profile.age}
|
} catch (error) {
|
||||||
- Gender: ${profile.gender}
|
// Fallback to basic prompt if context building fails
|
||||||
- Goal: ${profile.fitnessGoals.join(", ")}
|
console.warn('Failed to build AI context, using basic prompt:', error);
|
||||||
- Activity Level: ${profile.activityLevel}
|
prompt = buildBasicPrompt(profile);
|
||||||
- Medical Conditions: ${profile.medicalConditions || "None"}
|
|
||||||
- Injuries: ${profile.injuries || "None"}
|
|
||||||
|
|
||||||
Please provide the response in the following JSON format ONLY, no other text. Do not use markdown formatting or code blocks:
|
|
||||||
{
|
|
||||||
"recommendationText": "General advice and motivation for today.",
|
|
||||||
"activityPlan": "Detailed workout or activity plan for today.",
|
|
||||||
"dietPlan": "Detailed meal plan for today."
|
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
// Call Ollama
|
let parsedResponse;
|
||||||
|
|
||||||
|
if (useExternalModel) {
|
||||||
|
// Use DeepSeek AI
|
||||||
|
const deepseekApiKey = process.env.DEEPSEEK_API_KEY;
|
||||||
|
|
||||||
|
if (!deepseekApiKey) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "DeepSeek API key not configured" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Using DeepSeek AI model...");
|
||||||
|
|
||||||
|
const deepseekResponse = await fetch("https://api.deepseek.com/v1/chat/completions", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": `Bearer ${deepseekApiKey}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: "deepseek-chat",
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "system",
|
||||||
|
content: "You are a professional fitness trainer and nutritionist. Always respond with valid JSON only, no markdown or code blocks."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: prompt
|
||||||
|
}
|
||||||
|
],
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 1000,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!deepseekResponse.ok) {
|
||||||
|
const errorText = await deepseekResponse.text();
|
||||||
|
console.error("DeepSeek API error:", errorText);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Failed to generate recommendation from DeepSeek AI" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deepseekData = await deepseekResponse.json();
|
||||||
|
console.log("Raw DeepSeek Response:", deepseekData);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const content = deepseekData.choices[0].message.content;
|
||||||
|
let cleanResponse = content.trim();
|
||||||
|
|
||||||
|
// Remove markdown code blocks if present
|
||||||
|
if (cleanResponse.startsWith("```json")) {
|
||||||
|
cleanResponse = cleanResponse.replace(/^```json\s*/, "").replace(/\s*```$/, "");
|
||||||
|
} else if (cleanResponse.startsWith("```")) {
|
||||||
|
cleanResponse = cleanResponse.replace(/^```\s*/, "").replace(/\s*```$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the first '{' and last '}' to extract the JSON object
|
||||||
|
const firstBrace = cleanResponse.indexOf("{");
|
||||||
|
const lastBrace = cleanResponse.lastIndexOf("}");
|
||||||
|
|
||||||
|
if (firstBrace !== -1 && lastBrace !== -1) {
|
||||||
|
cleanResponse = cleanResponse.substring(firstBrace, lastBrace + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedResponse = JSON.parse(cleanResponse);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse DeepSeek response:", deepseekData);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Invalid response format from DeepSeek AI" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Use local Ollama
|
||||||
|
console.log("Using local Ollama model...");
|
||||||
|
|
||||||
const ollamaResponse = await fetch("http://localhost:11434/api/generate", {
|
const ollamaResponse = await fetch("http://localhost:11434/api/generate", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model: "gemma3:latest", // Make sure this model is pulled
|
model: "gemma3:latest",
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
stream: false,
|
stream: false,
|
||||||
format: "json",
|
format: "json",
|
||||||
@@ -59,17 +132,15 @@ export async function POST(req: Request) {
|
|||||||
if (!ollamaResponse.ok) {
|
if (!ollamaResponse.ok) {
|
||||||
console.error("Ollama API error:", await ollamaResponse.text());
|
console.error("Ollama API error:", await ollamaResponse.text());
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Failed to generate recommendation from AI service" },
|
{ error: "Failed to generate recommendation from Ollama" },
|
||||||
{ status: 500 }
|
{ status: 500 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiData = await ollamaResponse.json();
|
const aiData = await ollamaResponse.json();
|
||||||
console.log("Raw AI Response:", aiData.response);
|
console.log("Raw Ollama Response:", aiData.response);
|
||||||
|
|
||||||
let parsedResponse;
|
|
||||||
try {
|
try {
|
||||||
// Helper to clean up the response
|
|
||||||
let cleanResponse = aiData.response.trim();
|
let cleanResponse = aiData.response.trim();
|
||||||
|
|
||||||
// Remove markdown code blocks if present
|
// Remove markdown code blocks if present
|
||||||
@@ -89,21 +160,21 @@ export async function POST(req: Request) {
|
|||||||
|
|
||||||
parsedResponse = JSON.parse(cleanResponse);
|
parsedResponse = JSON.parse(cleanResponse);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Fallback if model doesn't return perfect JSON despite instruction
|
console.error("Failed to parse Ollama response:", aiData.response);
|
||||||
console.error("Failed to parse AI response:", aiData.response);
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Invalid response format from AI model" },
|
{ error: "Invalid response format from Ollama" },
|
||||||
{ status: 500 }
|
{ status: 500 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Save to database
|
// Save to database
|
||||||
const recommendation = await db.createRecommendation({
|
const recommendation = await db.createRecommendation({
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
userId,
|
userId,
|
||||||
fitnessProfileId: profile.userId, // Using userId as ID for now since it's 1:1
|
fitnessProfileId: profile.id,
|
||||||
type: 'ai_plan',
|
type: 'ai_plan',
|
||||||
content: parsedResponse.recommendationText,
|
recommendationText: parsedResponse.recommendationText,
|
||||||
activityPlan: parsedResponse.activityPlan,
|
activityPlan: parsedResponse.activityPlan,
|
||||||
dietPlan: parsedResponse.dietPlan,
|
dietPlan: parsedResponse.dietPlan,
|
||||||
status: 'pending'
|
status: 'pending'
|
||||||
|
|||||||
@@ -28,16 +28,22 @@ export async function GET(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check permissions: Users can view their own, Admins/Trainers can view anyone's
|
// Check permissions: Users can view their own, Admins/Trainers can view anyone's
|
||||||
if (currentUserId !== targetUserId) {
|
|
||||||
const currentUser = await db.getUserById(currentUserId)
|
const currentUser = await db.getUserById(currentUserId)
|
||||||
const isStaff = currentUser?.role === 'admin' || currentUser?.role === 'superAdmin' || currentUser?.role === 'trainer'
|
const isStaff = currentUser?.role === 'admin' || currentUser?.role === 'superAdmin' || currentUser?.role === 'trainer'
|
||||||
|
|
||||||
|
if (currentUserId !== targetUserId) {
|
||||||
if (!isStaff) {
|
if (!isStaff) {
|
||||||
return new NextResponse('Forbidden', { status: 403 })
|
return new NextResponse('Forbidden', { status: 403 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const recommendations = await db.getRecommendationsByUserId(targetUserId)
|
let recommendations = await db.getRecommendationsByUserId(targetUserId)
|
||||||
|
|
||||||
|
// Non-staff users should only see approved recommendations
|
||||||
|
if (!isStaff) {
|
||||||
|
recommendations = recommendations.filter((rec: any) => rec.status === 'approved')
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json(recommendations)
|
return NextResponse.json(recommendations)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching recommendations:', error)
|
console.error('Error fetching recommendations:', error)
|
||||||
@@ -70,7 +76,7 @@ export async function POST(request: Request) {
|
|||||||
userId,
|
userId,
|
||||||
fitnessProfileId,
|
fitnessProfileId,
|
||||||
type: 'ai_plan',
|
type: 'ai_plan',
|
||||||
content: recommendationText,
|
recommendationText: recommendationText,
|
||||||
activityPlan,
|
activityPlan,
|
||||||
dietPlan,
|
dietPlan,
|
||||||
status: status || 'pending'
|
status: status || 'pending'
|
||||||
@@ -84,7 +90,7 @@ export async function POST(request: Request) {
|
|||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
userId,
|
userId,
|
||||||
type,
|
type,
|
||||||
content,
|
recommendationText: content,
|
||||||
status: status || 'pending'
|
status: status || 'pending'
|
||||||
})
|
})
|
||||||
return NextResponse.json(recommendation)
|
return NextResponse.json(recommendation)
|
||||||
@@ -116,8 +122,8 @@ export async function PUT(request: Request) {
|
|||||||
|
|
||||||
const updated = await db.updateRecommendation(id, {
|
const updated = await db.updateRecommendation(id, {
|
||||||
...(status && { status }),
|
...(status && { status }),
|
||||||
...(recommendationText && { content: recommendationText }), // Map legacy field
|
...(recommendationText && { recommendationText }),
|
||||||
...(content && { content }),
|
...(content && { recommendationText: content }),
|
||||||
...(activityPlan && { activityPlan }),
|
...(activityPlan && { activityPlan }),
|
||||||
...(dietPlan && { dietPlan })
|
...(dietPlan && { dietPlan })
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { auth } from "@clerk/nextjs/server";
|
||||||
|
import { db, users as usersTable, eq, sql } from "@fitai/database";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PATCH /api/users/gym
|
||||||
|
* Body: { gymId: string | null }
|
||||||
|
* - Updates the current authenticated user's gym selection.
|
||||||
|
* - gymId can be null to proceed without a gym.
|
||||||
|
* - If gymId is provided, it must exist and be active.
|
||||||
|
*/
|
||||||
|
export async function PATCH(req: Request) {
|
||||||
|
try {
|
||||||
|
const { userId } = await auth();
|
||||||
|
console.log("PATCH /api/users/gym auth userId:", userId);
|
||||||
|
if (!userId) return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
|
||||||
|
const body = await req.json().catch(() => null);
|
||||||
|
if (!body || typeof body !== "object" || !("gymId" in body)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "gymId is required in body (can be null)" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gymId = body.gymId === null ? null : String(body.gymId);
|
||||||
|
console.log("PATCH /api/users/gym parsed gymId from body:", gymId);
|
||||||
|
|
||||||
|
// Ensure user exists
|
||||||
|
console.log("PATCH /api/users/gym fetching user by id:", userId);
|
||||||
|
const user = await db
|
||||||
|
.select()
|
||||||
|
.from(usersTable)
|
||||||
|
.where(eq(usersTable.id, userId))
|
||||||
|
.get();
|
||||||
|
console.log("PATCH /api/users/gym fetched user:", user);
|
||||||
|
if (!user) return new NextResponse("User not found", { status: 404 });
|
||||||
|
|
||||||
|
// Validate gym when provided
|
||||||
|
if (gymId) {
|
||||||
|
console.log("PATCH /api/users/gym validating gym:", gymId);
|
||||||
|
const rows = await db.all(
|
||||||
|
sql`SELECT status FROM gyms WHERE id = ${gymId} LIMIT 1`,
|
||||||
|
);
|
||||||
|
console.log("PATCH /api/users/gym validation query result rows:", rows);
|
||||||
|
const gym = rows?.[0] as { status?: string } | undefined;
|
||||||
|
if (!gym) {
|
||||||
|
console.log("PATCH /api/users/gym validation: gym not found");
|
||||||
|
return NextResponse.json({ error: "Gym not found" }, { status: 404 });
|
||||||
|
}
|
||||||
|
if (gym.status !== "active") {
|
||||||
|
console.log("PATCH /api/users/gym validation: gym not active", gym);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Gym is not active" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update user's gym selection
|
||||||
|
console.log("PATCH /api/users/gym updating user gym_id:", {
|
||||||
|
userId,
|
||||||
|
gymId,
|
||||||
|
});
|
||||||
|
await db.run(
|
||||||
|
sql`UPDATE users SET gym_id = ${gymId ?? null}, updated_at = ${new Date()} WHERE id = ${userId}`,
|
||||||
|
);
|
||||||
|
console.log("PATCH /api/users/gym update completed");
|
||||||
|
|
||||||
|
const updated = await db
|
||||||
|
.select()
|
||||||
|
.from(usersTable)
|
||||||
|
.where(eq(usersTable.id, userId))
|
||||||
|
.get();
|
||||||
|
console.log("PATCH /api/users/gym returning updated user:", updated);
|
||||||
|
return NextResponse.json(updated);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("PATCH /users/gym error:", error);
|
||||||
|
return new NextResponse("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
|
|||||||
import { getDatabase } from "../../../lib/database/index";
|
import { getDatabase } from "../../../lib/database/index";
|
||||||
import bcrypt from "bcryptjs";
|
import bcrypt from "bcryptjs";
|
||||||
import { auth, clerkClient } from "@clerk/nextjs/server";
|
import { auth, clerkClient } from "@clerk/nextjs/server";
|
||||||
|
import { db as rawDb, sql } from "@fitai/database";
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
@@ -11,18 +12,122 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
let users = await db.getAllUsers();
|
let users = await db.getAllUsers();
|
||||||
|
|
||||||
|
// Hydrate gymId from raw DB to ensure consistency with writes
|
||||||
|
const rawUserRows = await rawDb.all(sql`SELECT id, gym_id FROM users`);
|
||||||
|
const gymById = new Map<string, string | null>(
|
||||||
|
(rawUserRows || []).map((r: any) => [
|
||||||
|
r.id as string,
|
||||||
|
(r.gym_id as string | null) ?? null,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Load gym names for mapping gymId -> gymName
|
||||||
|
const gymRows = await rawDb.all(sql`SELECT id, name FROM gyms`);
|
||||||
|
const gymNames = new Map<string, string>(
|
||||||
|
(gymRows || [])
|
||||||
|
.filter((g: any) => !!g && typeof g.id === "string")
|
||||||
|
.map((g: any) => [
|
||||||
|
g.id as string,
|
||||||
|
(g.name as string) || (g.id as string),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
"GET /api/users: total users fetched from DB:",
|
||||||
|
Array.isArray(users) ? users.length : 0,
|
||||||
|
);
|
||||||
|
|
||||||
if (role) {
|
if (role) {
|
||||||
users = users.filter((user) => user.role === role);
|
users = users.filter((user) => user.role === role);
|
||||||
}
|
}
|
||||||
|
console.log(
|
||||||
|
"GET /api/users: role filter:",
|
||||||
|
role,
|
||||||
|
"users after filter:",
|
||||||
|
Array.isArray(users) ? users.length : 0,
|
||||||
|
"sample:",
|
||||||
|
users && users[0]
|
||||||
|
? {
|
||||||
|
id: users[0].id,
|
||||||
|
role: users[0].role,
|
||||||
|
gymId: (users as any)[0].gymId,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
const usersWithClients = await Promise.all(
|
const usersWithClients = await Promise.all(
|
||||||
users.map(async (user) => {
|
users.map(async (user) => {
|
||||||
const { password: _, ...userWithoutPassword } = user;
|
const { password: _, ...userWithoutPassword } = user;
|
||||||
const client = await db.getClientByUserId(user.id);
|
const client = await db.getClientByUserId(user.id);
|
||||||
return { ...userWithoutPassword, client };
|
|
||||||
|
// Get active check-in status and statistics for ALL users
|
||||||
|
let isCheckedIn = false;
|
||||||
|
let checkInTime = null;
|
||||||
|
let lastCheckInTime = null;
|
||||||
|
let checkInsThisWeek = 0;
|
||||||
|
let checkInsThisMonth = 0;
|
||||||
|
|
||||||
|
// Query attendance by userId (works for all user types now)
|
||||||
|
const activeCheckIn = await db.getActiveCheckIn(user.id);
|
||||||
|
if (activeCheckIn) {
|
||||||
|
isCheckedIn = true;
|
||||||
|
checkInTime = activeCheckIn.checkInTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get attendance history for statistics
|
||||||
|
const attendanceHistory = await db.getAttendanceHistory(user.id);
|
||||||
|
|
||||||
|
if (attendanceHistory.length > 0) {
|
||||||
|
// Last check-in is the most recent attendance record
|
||||||
|
lastCheckInTime = attendanceHistory[0].checkInTime;
|
||||||
|
|
||||||
|
// Calculate check-ins in last 7 days
|
||||||
|
const weekAgo = new Date();
|
||||||
|
weekAgo.setDate(weekAgo.getDate() - 7);
|
||||||
|
checkInsThisWeek = attendanceHistory.filter(
|
||||||
|
(a) => new Date(a.checkInTime) >= weekAgo,
|
||||||
|
).length;
|
||||||
|
|
||||||
|
// Calculate check-ins in last 30 days
|
||||||
|
const monthAgo = new Date();
|
||||||
|
monthAgo.setDate(monthAgo.getDate() - 30);
|
||||||
|
checkInsThisMonth = attendanceHistory.filter(
|
||||||
|
(a) => new Date(a.checkInTime) >= monthAgo,
|
||||||
|
).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...userWithoutPassword,
|
||||||
|
// Override gymId from raw DB hydration to avoid undefined from Drizzle mapping
|
||||||
|
gymId: gymById.get(user.id) ?? (user as any).gymId ?? undefined,
|
||||||
|
// Provide gymName mapped from gyms table
|
||||||
|
gymName: (() => {
|
||||||
|
const gid =
|
||||||
|
gymById.get(user.id) ?? (user as any).gymId ?? undefined;
|
||||||
|
if (!gid) return null;
|
||||||
|
return gymNames.get(gid) ?? null;
|
||||||
|
})(),
|
||||||
|
client,
|
||||||
|
isCheckedIn,
|
||||||
|
checkInTime,
|
||||||
|
lastCheckInTime,
|
||||||
|
checkInsThisWeek,
|
||||||
|
checkInsThisMonth,
|
||||||
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"GET /api/users: responding users count:",
|
||||||
|
Array.isArray(usersWithClients) ? usersWithClients.length : 0,
|
||||||
|
"sample:",
|
||||||
|
usersWithClients && usersWithClients[0]
|
||||||
|
? {
|
||||||
|
id: usersWithClients[0].id,
|
||||||
|
role: usersWithClients[0].role,
|
||||||
|
gymId: (usersWithClients as any)[0].gymId,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
return NextResponse.json({ users: usersWithClients });
|
return NextResponse.json({ users: usersWithClients });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Get users error:", error);
|
console.error("Get users error:", error);
|
||||||
@@ -60,7 +165,10 @@ export async function POST(request: NextRequest) {
|
|||||||
const currentUser = await db.getUserById(clerkUserId);
|
const currentUser = await db.getUserById(clerkUserId);
|
||||||
|
|
||||||
if (!currentUser) {
|
if (!currentUser) {
|
||||||
return NextResponse.json({ error: "Current user not found in database" }, { status: 403 });
|
return NextResponse.json(
|
||||||
|
{ error: "Current user not found in database" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
@@ -78,14 +186,14 @@ export async function POST(request: NextRequest) {
|
|||||||
superAdmin: ["admin", "trainer", "client"],
|
superAdmin: ["admin", "trainer", "client"],
|
||||||
admin: ["trainer", "client"],
|
admin: ["trainer", "client"],
|
||||||
trainer: ["client"],
|
trainer: ["client"],
|
||||||
client: []
|
client: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const userRole = currentUser.role as keyof typeof allowed;
|
const userRole = currentUser.role as keyof typeof allowed;
|
||||||
if (!allowed[userRole] || !allowed[userRole].includes(role)) {
|
if (!allowed[userRole] || !allowed[userRole].includes(role)) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: `You are not authorized to create a ${role}` },
|
{ error: `You are not authorized to create a ${role}` },
|
||||||
{ status: 403 }
|
{ status: 403 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,20 +215,24 @@ export async function POST(request: NextRequest) {
|
|||||||
publicMetadata: {
|
publicMetadata: {
|
||||||
role,
|
role,
|
||||||
},
|
},
|
||||||
ignoreExisting: true // Don't fail if invite exists
|
ignoreExisting: true, // Don't fail if invite exists
|
||||||
});
|
});
|
||||||
} catch (clerkError: any) {
|
} catch (clerkError: any) {
|
||||||
console.error("Clerk invitation error:", clerkError);
|
console.error("Clerk invitation error:", clerkError);
|
||||||
// If user already exists in Clerk, we might want to handle it.
|
// If user already exists in Clerk, we might want to handle it.
|
||||||
// But for now, let's proceed to create local record if invite sent or if they exist.
|
// But for now, let's proceed to create local record if invite sent or if they exist.
|
||||||
if (clerkError.errors?.[0]?.code === 'form_identifier_exists') {
|
if (clerkError.errors?.[0]?.code === "form_identifier_exists") {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "User already exists in Clerk system" },
|
{ error: "User already exists in Clerk system" },
|
||||||
{ status: 409 },
|
{ status: 409 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Failed to send invitation: " + (clerkError.message || "Unknown error") },
|
{
|
||||||
|
error:
|
||||||
|
"Failed to send invitation: " +
|
||||||
|
(clerkError.message || "Unknown error"),
|
||||||
|
},
|
||||||
{ status: 500 },
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -137,16 +249,19 @@ export async function POST(request: NextRequest) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If creating a client, create the client record too
|
// If creating a client, create the client record too
|
||||||
if (role === 'client') {
|
if (role === "client") {
|
||||||
await db.createClient({
|
await db.createClient({
|
||||||
userId: newUserId.id,
|
userId: newUserId.id,
|
||||||
membershipType: 'basic',
|
membershipType: "basic",
|
||||||
membershipStatus: 'active',
|
membershipStatus: "active",
|
||||||
joinDate: new Date()
|
joinDate: new Date(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({ userId: newUserId.id, message: "Invitation sent" }, { status: 201 });
|
return NextResponse.json(
|
||||||
|
{ userId: newUserId.id, message: "Invitation sent" },
|
||||||
|
{ status: 201 },
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Create user error:", error);
|
console.error("Create user error:", error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -160,7 +275,16 @@ export async function PUT(request: NextRequest) {
|
|||||||
try {
|
try {
|
||||||
const db = await getDatabase();
|
const db = await getDatabase();
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { id, email, firstName, lastName, role, phone } = body;
|
const { id, email, firstName, lastName, role, phone, gymId } = body;
|
||||||
|
console.log("PUT /api/users received body:", {
|
||||||
|
id,
|
||||||
|
email,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
role,
|
||||||
|
phone,
|
||||||
|
gymId,
|
||||||
|
});
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -169,12 +293,43 @@ export async function PUT(request: NextRequest) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get existing user
|
// Authenticate requester
|
||||||
|
const { userId: requesterId } = await auth();
|
||||||
|
if (!requesterId) {
|
||||||
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch requester and target user
|
||||||
|
const requester = await db.getUserById(requesterId);
|
||||||
|
if (!requester) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Requester not found" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const existingUser = await db.getUserById(id);
|
const existingUser = await db.getUserById(id);
|
||||||
if (!existingUser) {
|
if (!existingUser) {
|
||||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Authorization: determine allowed role changes
|
||||||
|
const requesterRole = requester.role;
|
||||||
|
const allowedByRole: Record<string, string[]> = {
|
||||||
|
superAdmin: ["superAdmin", "admin", "trainer", "client", "generalUser"],
|
||||||
|
admin: ["admin", "trainer", "client", "generalUser"],
|
||||||
|
trainer: [], // trainers cannot change roles
|
||||||
|
client: [], // clients cannot change roles
|
||||||
|
generalUser: [], // general users cannot change roles
|
||||||
|
};
|
||||||
|
|
||||||
|
if (role && !allowedByRole[requesterRole]?.includes(role)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: `Not authorized to assign role '${role}'` },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if email is being changed and if it's already taken
|
// Check if email is being changed and if it's already taken
|
||||||
if (email && email !== existingUser.email) {
|
if (email && email !== existingUser.email) {
|
||||||
const userWithEmail = await db.getUserByEmail(email);
|
const userWithEmail = await db.getUserByEmail(email);
|
||||||
@@ -186,16 +341,86 @@ export async function PUT(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update user
|
// Update Clerk publicMetadata (role/gymId) to propagate via webhook
|
||||||
await db.updateUser(id, {
|
// Note: Only update metadata when a change is requested
|
||||||
email: email || existingUser.email,
|
try {
|
||||||
firstName: firstName || existingUser.firstName,
|
const client = await clerkClient();
|
||||||
lastName: lastName || existingUser.lastName,
|
const publicMetadata: Record<string, unknown> = {};
|
||||||
role: role || existingUser.role,
|
console.log("PUT /api/users preparing Clerk metadata update:", {
|
||||||
phone: phone !== undefined ? phone : existingUser.phone,
|
targetUserId: id,
|
||||||
|
role,
|
||||||
|
gymId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
if (role) {
|
||||||
|
publicMetadata.role = role;
|
||||||
|
}
|
||||||
|
if (gymId !== undefined) {
|
||||||
|
publicMetadata.gymId = gymId === null ? null : String(gymId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(publicMetadata).length > 0) {
|
||||||
|
console.log(
|
||||||
|
"PUT /api/users calling Clerk updateUser with metadata:",
|
||||||
|
publicMetadata,
|
||||||
|
);
|
||||||
|
const clerkResult = await client.users.updateUser(id, {
|
||||||
|
publicMetadata,
|
||||||
|
});
|
||||||
|
console.log("PUT /api/users Clerk updateUser result:", {
|
||||||
|
id: clerkResult.id,
|
||||||
|
role: clerkResult.publicMetadata?.role,
|
||||||
|
gymId: clerkResult.publicMetadata?.gymId,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("PUT /api/users no Clerk metadata changes requested");
|
||||||
|
}
|
||||||
|
} catch (clerkErr: any) {
|
||||||
|
console.error("Clerk metadata update error:", clerkErr);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Failed to update role/gym in identity provider" },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update local DB for immediate UI feedback (webhook will also sync)
|
||||||
|
console.log(
|
||||||
|
"PUT /api/users raw SQL updating local DB user gym_id and fields",
|
||||||
|
);
|
||||||
|
await rawDb.run(
|
||||||
|
sql`UPDATE users
|
||||||
|
SET email = ${email ?? existingUser.email},
|
||||||
|
first_name = ${firstName ?? existingUser.firstName},
|
||||||
|
last_name = ${lastName ?? existingUser.lastName},
|
||||||
|
role = ${role ?? existingUser.role},
|
||||||
|
phone = ${phone !== undefined && typeof phone === "string" ? phone : (existingUser.phone ?? null)},
|
||||||
|
gym_id = ${gymId !== undefined ? gymId : (existingUser.gymId ?? null)},
|
||||||
|
updated_at = ${Date.now()}
|
||||||
|
WHERE id = ${id}`,
|
||||||
|
);
|
||||||
|
// Read back the updated row to surface gym_id and confirm write
|
||||||
|
const updatedRow = await rawDb.get(
|
||||||
|
sql`SELECT id, email, first_name, last_name, role, phone, gym_id, created_at, updated_at FROM users WHERE id = ${id}`,
|
||||||
|
);
|
||||||
|
console.log("PUT /api/users raw DB row after update:", updatedRow);
|
||||||
|
|
||||||
|
const updatedUser = {
|
||||||
|
...existingUser,
|
||||||
|
email: email ?? existingUser.email,
|
||||||
|
firstName: firstName ?? existingUser.firstName,
|
||||||
|
lastName: lastName ?? existingUser.lastName,
|
||||||
|
role: role ?? existingUser.role,
|
||||||
|
phone: phone !== undefined ? phone : existingUser.phone,
|
||||||
|
gymId:
|
||||||
|
updatedRow?.gym_id !== undefined
|
||||||
|
? updatedRow.gym_id
|
||||||
|
: gymId !== undefined
|
||||||
|
? gymId
|
||||||
|
: existingUser.gymId,
|
||||||
|
};
|
||||||
|
console.log("PUT /api/users responding with updated user:", updatedUser);
|
||||||
|
|
||||||
|
return NextResponse.json({ user: updatedUser });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Update user error:", error);
|
console.error("Update user error:", error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -78,15 +78,31 @@ export async function POST(req: Request) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine role from metadata or default to 'client'
|
// Determine role & gym from metadata
|
||||||
const role =
|
const role =
|
||||||
(public_metadata?.role as "admin" | "trainer" | "client") || "client";
|
(public_metadata?.role as
|
||||||
|
| "superAdmin"
|
||||||
|
| "admin"
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "generalUser") || "client";
|
||||||
|
let gymId = (public_metadata?.gymId as string | null) ?? null;
|
||||||
|
const inviterUserId =
|
||||||
|
(public_metadata?.inviterUserId as string | undefined) ?? undefined;
|
||||||
|
const roleAssigned =
|
||||||
|
(public_metadata?.roleAssigned as
|
||||||
|
| "superAdmin"
|
||||||
|
| "admin"
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "generalUser"
|
||||||
|
| undefined) ?? role;
|
||||||
|
|
||||||
// Insert user into database with Clerk's user ID
|
// Insert user into database with Clerk's user ID
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
INSERT INTO users (id, email, firstName, lastName, password, phone, role, createdAt, updatedAt)
|
INSERT INTO users (id, email, first_name, last_name, password, phone, role, gym_id, created_at, updated_at)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
stmt.run(
|
stmt.run(
|
||||||
@@ -97,11 +113,57 @@ export async function POST(req: Request) {
|
|||||||
"", // Clerk handles authentication
|
"", // Clerk handles authentication
|
||||||
null, // phone
|
null, // phone
|
||||||
role,
|
role,
|
||||||
|
gymId,
|
||||||
now,
|
now,
|
||||||
now,
|
now,
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`✅ User ${id} created in database`);
|
// If this is a client invited by a trainer, create trainer-client link
|
||||||
|
if (roleAssigned === "client" && inviterUserId && gymId) {
|
||||||
|
const inviterRow = db
|
||||||
|
.prepare("SELECT role FROM users WHERE id = ?")
|
||||||
|
.get(inviterUserId) as { role?: string } | undefined;
|
||||||
|
|
||||||
|
if (inviterRow?.role === "trainer") {
|
||||||
|
const linkId = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
||||||
|
const linkStmt = db.prepare(`
|
||||||
|
INSERT INTO trainer_clients (id, trainer_user_id, client_user_id, gym_id, created_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
linkStmt.run(
|
||||||
|
linkId,
|
||||||
|
inviterUserId,
|
||||||
|
id,
|
||||||
|
gymId,
|
||||||
|
new Date().toISOString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a trainer without a gymId but has an inviter, inherit inviter's gymId
|
||||||
|
if (
|
||||||
|
(roleAssigned === "trainer" || role === "trainer") &&
|
||||||
|
!gymId &&
|
||||||
|
inviterUserId
|
||||||
|
) {
|
||||||
|
const inviterGymRow = db
|
||||||
|
.prepare("SELECT gym_id FROM users WHERE id = ?")
|
||||||
|
.get(inviterUserId) as { gym_id?: string } | undefined;
|
||||||
|
|
||||||
|
if (inviterGymRow?.gym_id) {
|
||||||
|
const inheritStmt = db.prepare(`
|
||||||
|
UPDATE users
|
||||||
|
SET gym_id = ?, updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`);
|
||||||
|
inheritStmt.run(inviterGymRow.gym_id, new Date().toISOString(), id);
|
||||||
|
gymId = inviterGymRow.gym_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`✅ User ${id} created in database (role=${role}, gymId=${gymId ?? "null"})`,
|
||||||
|
);
|
||||||
db.close();
|
db.close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -124,15 +186,21 @@ export async function POST(req: Request) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine role from metadata
|
// Determine role & gym from metadata
|
||||||
const role =
|
const role =
|
||||||
(public_metadata?.role as "admin" | "trainer" | "client") || "client";
|
(public_metadata?.role as
|
||||||
|
| "superAdmin"
|
||||||
|
| "admin"
|
||||||
|
| "trainer"
|
||||||
|
| "client"
|
||||||
|
| "generalUser") || "client";
|
||||||
|
let gymId = (public_metadata?.gymId as string | null) ?? null;
|
||||||
|
|
||||||
// Update user in database
|
// Update user in database
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET email = ?, firstName = ?, lastName = ?, role = ?, updatedAt = ?
|
SET email = ?, first_name = ?, last_name = ?, role = ?, gym_id = ?, updated_at = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -141,10 +209,33 @@ export async function POST(req: Request) {
|
|||||||
first_name || "",
|
first_name || "",
|
||||||
last_name || "",
|
last_name || "",
|
||||||
role,
|
role,
|
||||||
|
gymId,
|
||||||
now,
|
now,
|
||||||
id,
|
id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If user is a trainer and gymId is missing, attempt to inherit from inviter when available
|
||||||
|
if (
|
||||||
|
role === "trainer" &&
|
||||||
|
!gymId &&
|
||||||
|
evt.data.public_metadata?.inviterUserId
|
||||||
|
) {
|
||||||
|
const inviterUserId = String(evt.data.public_metadata.inviterUserId);
|
||||||
|
const inviterGymRow = db
|
||||||
|
.prepare("SELECT gym_id FROM users WHERE id = ?")
|
||||||
|
.get(inviterUserId) as { gym_id?: string } | undefined;
|
||||||
|
|
||||||
|
if (inviterGymRow?.gym_id) {
|
||||||
|
const inheritStmt = db.prepare(`
|
||||||
|
UPDATE users
|
||||||
|
SET gym_id = ?, updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`);
|
||||||
|
inheritStmt.run(inviterGymRow.gym_id, new Date().toISOString(), id);
|
||||||
|
gymId = inviterGymRow.gym_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`✅ User ${id} updated in database`);
|
console.log(`✅ User ${id} updated in database`);
|
||||||
db.close();
|
db.close();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function RootLayout({
|
|||||||
<body className={inter.className}>
|
<body className={inter.className}>
|
||||||
<div className="flex min-h-screen bg-slate-50">
|
<div className="flex min-h-screen bg-slate-50">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main className="flex-1 ml-64 p-8">
|
<main className="flex-1 ml-20 p-8">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -87,12 +87,11 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<div className="lg:col-span-2 bg-white rounded-xl shadow-sm border border-slate-100 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
|
||||||
<h3 className="text-xl font-bold text-slate-900 mb-6">Recent Activity</h3>
|
<h3 className="text-xl font-bold text-slate-900 mb-6">Recent Activity</h3>
|
||||||
<UserManagement />
|
<UserManagement />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
|
||||||
<h3 className="text-xl font-bold text-slate-900 mb-6">Quick Analytics</h3>
|
<h3 className="text-xl font-bold text-slate-900 mb-6">Quick Analytics</h3>
|
||||||
<AnalyticsDashboard />
|
<AnalyticsDashboard />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useUser } from "@clerk/nextjs";
|
import { useUser } from "@clerk/nextjs";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
|
||||||
interface UserProfile {
|
interface UserProfile {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export default function RecommendationsPage() {
|
|||||||
const [pendingRecommendations, setPendingRecommendations] = useState<any[]>([]);
|
const [pendingRecommendations, setPendingRecommendations] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [generating, setGenerating] = useState<string | null>(null);
|
const [generating, setGenerating] = useState<string | null>(null);
|
||||||
|
const [useExternalModel, setUseExternalModel] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
@@ -56,7 +57,7 @@ export default function RecommendationsPage() {
|
|||||||
const res = await fetch("/api/recommendations/generate", {
|
const res = await fetch("/api/recommendations/generate", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ userId }),
|
body: JSON.stringify({ userId, useExternalModel }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
@@ -98,6 +99,41 @@ export default function RecommendationsPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEdit = async (rec: Recommendation) => {
|
||||||
|
const newContent = prompt("Edit Advice:", rec.content);
|
||||||
|
const newActivityPlan = prompt("Edit Activity Plan:", rec.activityPlan);
|
||||||
|
const newDietPlan = prompt("Edit Diet Plan:", rec.dietPlan);
|
||||||
|
|
||||||
|
if (newContent === null || newActivityPlan === null || newDietPlan === null) {
|
||||||
|
// User cancelled one of the prompts
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/recommendations", {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: rec.id,
|
||||||
|
content: newContent,
|
||||||
|
activityPlan: newActivityPlan,
|
||||||
|
dietPlan: newDietPlan,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const errorData = await res.json();
|
||||||
|
alert(`Failed to update recommendation: ${errorData.error || 'Unknown error'}`);
|
||||||
|
} else {
|
||||||
|
alert("Recommendation updated successfully!");
|
||||||
|
fetchData(); // Refresh data
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating recommendation:", error);
|
||||||
|
alert("Failed to update recommendation.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen">
|
<div className="flex items-center justify-center h-screen">
|
||||||
@@ -108,7 +144,29 @@ export default function RecommendationsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto py-10 px-4">
|
<div className="container mx-auto py-10 px-4">
|
||||||
<h1 className="text-3xl font-bold mb-8">AI Recommendations</h1>
|
<div className="flex justify-between items-center mb-8">
|
||||||
|
<h1 className="text-3xl font-bold">AI Recommendations</h1>
|
||||||
|
|
||||||
|
{/* Model Selection Toggle */}
|
||||||
|
<div className="flex items-center gap-3 bg-white px-4 py-2 rounded-lg shadow">
|
||||||
|
<span className="text-sm font-medium text-gray-700">
|
||||||
|
{useExternalModel ? "DeepSeek AI" : "Local Ollama"}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setUseExternalModel(!useExternalModel)}
|
||||||
|
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${useExternalModel ? "bg-blue-600" : "bg-gray-300"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${useExternalModel ? "translate-x-6" : "translate-x-1"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<span className="text-xs text-gray-500">
|
||||||
|
{useExternalModel ? "External" : "Local"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||||
{/* Generate Section */}
|
{/* Generate Section */}
|
||||||
@@ -161,7 +219,7 @@ export default function RecommendationsPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2 text-sm mb-4">
|
<div className="space-y-2 text-sm mb-4">
|
||||||
<div>
|
<div>
|
||||||
<span className="font-semibold">Advice:</span> {rec.content}
|
<span className="font-semibold">Advice:</span> {rec.recommendationText}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="font-semibold">Activity:</span> {rec.activityPlan}
|
<span className="font-semibold">Activity:</span> {rec.activityPlan}
|
||||||
@@ -171,6 +229,12 @@ export default function RecommendationsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
|
<button
|
||||||
|
onClick={() => handleEdit(rec)}
|
||||||
|
className="flex-1 bg-blue-500 text-white py-2 rounded hover:bg-blue-600"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleApprove(rec.id, "approved")}
|
onClick={() => handleApprove(rec.id, "approved")}
|
||||||
className="flex-1 bg-green-600 text-white py-2 rounded hover:bg-green-700"
|
className="flex-1 bg-green-600 text-white py-2 rounded hover:bg-green-700"
|
||||||
|
|||||||
@@ -0,0 +1,486 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
import {
|
||||||
|
Database,
|
||||||
|
Download,
|
||||||
|
RefreshCw,
|
||||||
|
AlertTriangle,
|
||||||
|
Check,
|
||||||
|
Loader2,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { useUser } from "@clerk/nextjs";
|
||||||
|
|
||||||
|
interface Backup {
|
||||||
|
name: string;
|
||||||
|
size: number;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Gym {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
location?: string | null;
|
||||||
|
status: "active" | "inactive";
|
||||||
|
adminUserId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SettingsPage() {
|
||||||
|
const { user } = useUser();
|
||||||
|
const [backups, setBackups] = useState<Backup[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [creatingBackup, setCreatingBackup] = useState(false);
|
||||||
|
const [restoring, setRestoring] = useState<string | null>(null);
|
||||||
|
const [message, setMessage] = useState<{
|
||||||
|
type: "success" | "error";
|
||||||
|
text: string;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
|
// Gym picker state
|
||||||
|
const [gyms, setGyms] = useState<Gym[]>([]);
|
||||||
|
const [gymsLoading, setGymsLoading] = useState<boolean>(true);
|
||||||
|
const [gymMessage, setGymMessage] = useState<{
|
||||||
|
type: "success" | "error";
|
||||||
|
text: string;
|
||||||
|
} | null>(null);
|
||||||
|
// Create Gym modal state
|
||||||
|
const [showCreateGym, setShowCreateGym] = useState(false);
|
||||||
|
const [gymName, setGymName] = useState("");
|
||||||
|
const [gymLocation, setGymLocation] = useState("");
|
||||||
|
const [creatingGym, setCreatingGym] = useState(false);
|
||||||
|
|
||||||
|
const fetchBackups = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get("/api/admin/backups");
|
||||||
|
setBackups(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch backups:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchGyms = async () => {
|
||||||
|
setGymsLoading(true);
|
||||||
|
setGymMessage(null);
|
||||||
|
try {
|
||||||
|
const res = await axios.get("/api/gyms");
|
||||||
|
setGyms(Array.isArray(res.data) ? res.data : []);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch gyms:", error);
|
||||||
|
setGymMessage({ type: "error", text: "Failed to load gyms" });
|
||||||
|
} finally {
|
||||||
|
setGymsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchBackups();
|
||||||
|
fetchGyms();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleCreateBackup = async () => {
|
||||||
|
setCreatingBackup(true);
|
||||||
|
setMessage(null);
|
||||||
|
try {
|
||||||
|
await axios.post("/api/admin/backups");
|
||||||
|
await fetchBackups();
|
||||||
|
setMessage({ type: "success", text: "Backup created successfully" });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to create backup:", error);
|
||||||
|
setMessage({ type: "error", text: "Failed to create backup" });
|
||||||
|
} finally {
|
||||||
|
setCreatingBackup(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRestore = async (filename: string) => {
|
||||||
|
if (
|
||||||
|
!window.confirm(
|
||||||
|
`Are you sure you want to restore from ${filename}? This will overwrite the current database.`,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setRestoring(filename);
|
||||||
|
setMessage(null);
|
||||||
|
try {
|
||||||
|
await axios.post("/api/admin/backups/restore", { filename });
|
||||||
|
setMessage({ type: "success", text: "Database restored successfully" });
|
||||||
|
// Optional: Refresh page or force re-login if session is invalidated
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to restore backup:", error);
|
||||||
|
setMessage({ type: "error", text: "Failed to restore backup" });
|
||||||
|
} finally {
|
||||||
|
setRestoring(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatSize = (bytes: number) => {
|
||||||
|
const units = ["B", "KB", "MB", "GB"];
|
||||||
|
let size = bytes;
|
||||||
|
let unitIndex = 0;
|
||||||
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||||
|
size /= 1024;
|
||||||
|
unitIndex++;
|
||||||
|
}
|
||||||
|
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (dateString: string) => {
|
||||||
|
return new Date(dateString).toLocaleString();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectGym = async (gymId: string | null) => {
|
||||||
|
setGymMessage(null);
|
||||||
|
try {
|
||||||
|
// Update current user's gym selection
|
||||||
|
await axios.patch("/api/users/gym", { gymId });
|
||||||
|
setGymMessage({
|
||||||
|
type: "success",
|
||||||
|
text: gymId ? "Gym selected successfully" : "Proceeding without gym",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to set gym:", error);
|
||||||
|
setGymMessage({ type: "error", text: "Failed to set gym" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-8 p-8">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-3xl font-bold text-slate-900">Settings</h2>
|
||||||
|
<p className="text-slate-500 mt-2">
|
||||||
|
Manage your application settings and database.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Gym Picker */}
|
||||||
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-2 bg-blue-50 rounded-lg">
|
||||||
|
<Database className="w-6 h-6 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-slate-900">
|
||||||
|
Gym Selection
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-slate-500">
|
||||||
|
Select your gym or proceed without a gym
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-blue-600 mt-1">
|
||||||
|
{user ? (
|
||||||
|
<>
|
||||||
|
Current role:{" "}
|
||||||
|
<span className="font-medium">
|
||||||
|
{String(user.publicMetadata?.role ?? "unknown")}
|
||||||
|
</span>
|
||||||
|
{" • "}
|
||||||
|
Gym ID:{" "}
|
||||||
|
<span className="font-medium">
|
||||||
|
{String(user.publicMetadata?.gymId ?? "none")}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"Loading user metadata..."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
onClick={fetchGyms}
|
||||||
|
disabled={gymsLoading}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
{gymsLoading ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<RefreshCw className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
Refresh Gyms
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => setShowCreateGym(true)}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
Create Gym
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{gymMessage && (
|
||||||
|
<div
|
||||||
|
className={`p-4 rounded-lg mb-6 flex items-center gap-2 ${gymMessage.type === "success" ? "bg-green-50 text-green-700" : "bg-red-50 text-red-700"}`}
|
||||||
|
>
|
||||||
|
{gymMessage.type === "success" ? (
|
||||||
|
<Check className="w-5 h-5" />
|
||||||
|
) : (
|
||||||
|
<AlertTriangle className="w-5 h-5" />
|
||||||
|
)}
|
||||||
|
{gymMessage.text}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{showCreateGym && (
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
|
<div className="bg-white p-6 rounded-lg shadow-lg max-w-md w-full">
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Create Gym</h3>
|
||||||
|
<form
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
setCreatingGym(true);
|
||||||
|
await axios.post("/api/gyms", {
|
||||||
|
name: gymName.trim(),
|
||||||
|
location: gymLocation.trim() || undefined,
|
||||||
|
});
|
||||||
|
setGymMessage({
|
||||||
|
type: "success",
|
||||||
|
text: "Gym created successfully",
|
||||||
|
});
|
||||||
|
setShowCreateGym(false);
|
||||||
|
setGymName("");
|
||||||
|
setGymLocation("");
|
||||||
|
fetchGyms();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to create gym:", error);
|
||||||
|
setGymMessage({
|
||||||
|
type: "error",
|
||||||
|
text: "Failed to create gym",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setCreatingGym(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Gym Name
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={gymName}
|
||||||
|
onChange={(e) => setGymName(e.target.value)}
|
||||||
|
className="w-full border border-gray-300 rounded px-3 py-2"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Location (optional)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={gymLocation}
|
||||||
|
onChange={(e) => setGymLocation(e.target.value)}
|
||||||
|
className="w-full border border-gray-300 rounded px-3 py-2"
|
||||||
|
placeholder="Enter location"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setShowCreateGym(false);
|
||||||
|
setGymName("");
|
||||||
|
setGymLocation("");
|
||||||
|
}}
|
||||||
|
className="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={creatingGym}
|
||||||
|
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 flex items-center gap-2"
|
||||||
|
>
|
||||||
|
{creatingGym ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : null}
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
<div className="border rounded-lg p-4 flex flex-col justify-between">
|
||||||
|
<div>
|
||||||
|
<h4 className="font-semibold text-slate-900">
|
||||||
|
Proceed without gym
|
||||||
|
</h4>
|
||||||
|
<p className="text-sm text-slate-600 mt-1">
|
||||||
|
You can select a gym later.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="mt-4"
|
||||||
|
onClick={() => handleSelectGym(null)}
|
||||||
|
>
|
||||||
|
Proceed without gym
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{gymsLoading ? (
|
||||||
|
<div className="col-span-full flex items-center justify-center p-8 text-slate-500">
|
||||||
|
<Loader2 className="w-5 h-5 animate-spin mr-2" />
|
||||||
|
Loading gyms...
|
||||||
|
</div>
|
||||||
|
) : gyms.length === 0 ? (
|
||||||
|
<div className="col-span-full p-8 text-center text-slate-500">
|
||||||
|
No active gyms found.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
gyms.map((gym) => (
|
||||||
|
<div
|
||||||
|
key={gym.id}
|
||||||
|
className="border rounded-lg p-4 flex flex-col justify-between"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h4 className="font-semibold text-slate-900">{gym.name}</h4>
|
||||||
|
<p className="text-sm text-slate-600 mt-1">
|
||||||
|
{gym.location || "No location provided"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
className="mt-4"
|
||||||
|
onClick={() => handleSelectGym(gym.id)}
|
||||||
|
>
|
||||||
|
Select this gym
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-2 bg-blue-50 rounded-lg">
|
||||||
|
<Database className="w-6 h-6 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-slate-900">
|
||||||
|
Database Management
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-slate-500">
|
||||||
|
Create backups and restore your database
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={handleCreateBackup}
|
||||||
|
disabled={creatingBackup}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
{creatingBackup ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Download className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
Create Backup
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<div
|
||||||
|
className={`p-4 rounded-lg mb-6 flex items-center gap-2 ${
|
||||||
|
message.type === "success"
|
||||||
|
? "bg-green-50 text-green-700"
|
||||||
|
: "bg-red-50 text-red-700"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{message.type === "success" ? (
|
||||||
|
<Check className="w-5 h-5" />
|
||||||
|
) : (
|
||||||
|
<AlertTriangle className="w-5 h-5" />
|
||||||
|
)}
|
||||||
|
{message.text}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="border rounded-lg overflow-hidden">
|
||||||
|
<table className="w-full text-left text-sm">
|
||||||
|
<thead className="bg-slate-50 border-b">
|
||||||
|
<tr>
|
||||||
|
<th className="px-6 py-4 font-semibold text-slate-900">
|
||||||
|
Filename
|
||||||
|
</th>
|
||||||
|
<th className="px-6 py-4 font-semibold text-slate-900">Size</th>
|
||||||
|
<th className="px-6 py-4 font-semibold text-slate-900">
|
||||||
|
Created At
|
||||||
|
</th>
|
||||||
|
<th className="px-6 py-4 font-semibold text-slate-900 text-right">
|
||||||
|
Actions
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y">
|
||||||
|
{loading ? (
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={4}
|
||||||
|
className="px-6 py-8 text-center text-slate-500"
|
||||||
|
>
|
||||||
|
Loading backups...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : backups.length === 0 ? (
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={4}
|
||||||
|
className="px-6 py-8 text-center text-slate-500"
|
||||||
|
>
|
||||||
|
No backups found
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : (
|
||||||
|
backups.map((backup) => (
|
||||||
|
<tr
|
||||||
|
key={backup.name}
|
||||||
|
className="hover:bg-slate-50 transition-colors"
|
||||||
|
>
|
||||||
|
<td className="px-6 py-4 font-medium text-slate-900">
|
||||||
|
{backup.name}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4 text-slate-600">
|
||||||
|
{formatSize(backup.size)}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4 text-slate-600">
|
||||||
|
{formatDate(backup.createdAt)}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4 text-right">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleRestore(backup.name)}
|
||||||
|
disabled={!!restoring}
|
||||||
|
className="text-red-600 hover:text-red-700 hover:bg-red-50"
|
||||||
|
>
|
||||||
|
{restoring === backup.name ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
|
)}
|
||||||
|
Restore
|
||||||
|
</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,10 +3,10 @@
|
|||||||
import { type ReactElement } from "react";
|
import { type ReactElement } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { Home, Users, BarChart3, User, Brain } from "lucide-react";
|
import { Home, Users, BarChart3, User, Brain, Settings } from "lucide-react";
|
||||||
import { SignedIn, UserButton } from "@clerk/nextjs";
|
import { SignedIn, UserButton } from "@clerk/nextjs";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
interface NavItem {
|
interface NavItem {
|
||||||
href: string;
|
href: string;
|
||||||
@@ -40,6 +40,11 @@ const navItems: NavItem[] = [
|
|||||||
label: "Profile",
|
label: "Profile",
|
||||||
icon: User,
|
icon: User,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
href: "/settings",
|
||||||
|
label: "Settings",
|
||||||
|
icon: Settings,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function Navigation(): ReactElement {
|
export function Navigation(): ReactElement {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export function AnalyticsDashboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6 w-full">
|
||||||
<h2 className="text-2xl font-bold">Analytics Dashboard</h2>
|
<h2 className="text-2xl font-bold">Analytics Dashboard</h2>
|
||||||
|
|
||||||
{/* Key Metrics */}
|
{/* Key Metrics */}
|
||||||
@@ -132,7 +132,13 @@ export function AnalyticsDashboard() {
|
|||||||
<h3 className="text-lg font-semibold">Monthly Revenue</h3>
|
<h3 className="text-lg font-semibold">Monthly Revenue</h3>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<RevenueChart data={revenueData} />
|
<RevenueChart
|
||||||
|
data={revenueData.map(item => ({
|
||||||
|
category: item.label,
|
||||||
|
value: item.value,
|
||||||
|
color: item.color
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
||||||
variant?: 'primary' | 'secondary'
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Button({ variant = 'primary', children, className = '', ...props }: ButtonProps) {
|
|
||||||
const baseClasses = 'px-4 py-2 rounded-md font-medium transition-colors'
|
|
||||||
const variantClasses = {
|
|
||||||
primary: 'bg-blue-600 text-white hover:bg-blue-700',
|
|
||||||
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className={`${baseClasses} ${variantClasses[variant]} ${className}`}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
interface CardProps {
|
|
||||||
children: React.ReactNode
|
|
||||||
className?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Card({ children, className = '' }: CardProps) {
|
|
||||||
return (
|
|
||||||
<div className={`bg-white rounded-lg shadow-md p-6 ${className}`}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CardHeader({ children, className = '' }: CardProps) {
|
|
||||||
return (
|
|
||||||
<div className={`mb-4 ${className}`}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CardContent({ children, className = '' }: CardProps) {
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
Users,
|
Users,
|
||||||
@@ -9,27 +10,64 @@ import {
|
|||||||
CreditCard,
|
CreditCard,
|
||||||
Settings,
|
Settings,
|
||||||
LogOut,
|
LogOut,
|
||||||
Brain
|
Brain,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { UserButton, useUser } from "@clerk/nextjs";
|
import { UserButton, useUser } from "@clerk/nextjs";
|
||||||
|
|
||||||
const menuItems = [
|
interface Recommendation {
|
||||||
{ icon: LayoutDashboard, label: "Dashboard", href: "/" },
|
id: string;
|
||||||
{ icon: Users, label: "Users", href: "/users" },
|
status: string;
|
||||||
{ icon: Brain, label: "AI Recommendations", href: "/recommendations" },
|
}
|
||||||
{ icon: CalendarCheck, label: "Attendance", href: "/attendance" },
|
|
||||||
{ icon: CreditCard, label: "Payments", href: "/payments" },
|
|
||||||
{ icon: Settings, label: "Settings", href: "/settings" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function Sidebar() {
|
export function Sidebar() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
const [pendingCount, setPendingCount] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchPending = async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/recommendations");
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
const pending = (data.recommendations || []).filter(
|
||||||
|
(r: Recommendation) => r.status === "pending"
|
||||||
|
);
|
||||||
|
setPendingCount(pending.length);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to fetch pending recommendations", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchPending();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const menuItems = [
|
||||||
|
{ icon: LayoutDashboard, label: "Dashboard", href: "/" },
|
||||||
|
{ icon: Users, label: "Users", href: "/users" },
|
||||||
|
{
|
||||||
|
icon: Brain,
|
||||||
|
label: (
|
||||||
|
<span className="flex items-center">
|
||||||
|
AI Recommendations
|
||||||
|
{pendingCount > 0 && (
|
||||||
|
<span className="ml-2 inline-block bg-red-600 text-xs rounded-full px-2 py-0.5">
|
||||||
|
{pendingCount}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
href: "/recommendations",
|
||||||
|
},
|
||||||
|
{ icon: CalendarCheck, label: "Attendance", href: "/attendance" },
|
||||||
|
{ icon: CreditCard, label: "Payments", href: "/payments" },
|
||||||
|
{ icon: Settings, label: "Settings", href: "/settings" },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-64 bg-slate-900 text-white h-screen fixed left-0 top-0 flex flex-col border-r border-slate-800">
|
<aside className="w-20 hover:w-64 bg-slate-900 text-white h-screen fixed left-0 top-0 flex flex-col border-r border-slate-800 transition-all duration-300 z-50 group overflow-hidden">
|
||||||
<div className="p-6 border-b border-slate-800">
|
<div className="p-6 border-b border-slate-800 flex items-center overflow-hidden whitespace-nowrap">
|
||||||
<h1 className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-indigo-400 bg-clip-text text-transparent">
|
<h1 className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-indigo-400 bg-clip-text text-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
FitAI Admin
|
FitAI Admin
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,27 +76,32 @@ export function Sidebar() {
|
|||||||
{menuItems.map((item) => {
|
{menuItems.map((item) => {
|
||||||
const Icon = item.icon;
|
const Icon = item.icon;
|
||||||
const isActive = pathname === item.href;
|
const isActive = pathname === item.href;
|
||||||
|
const label = typeof item.label === "string" ? item.label : item.label;
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={item.href}
|
key={item.href}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className={`flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 group ${isActive
|
className={`flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 ${isActive
|
||||||
? "bg-blue-600 text-white shadow-lg shadow-blue-900/20"
|
? "bg-blue-600 text-white shadow-lg shadow-blue-900/20"
|
||||||
: "text-slate-400 hover:bg-slate-800 hover:text-white"
|
: "text-slate-400 hover:bg-slate-800 hover:text-white"}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
|
<div className="min-w-[20px]">
|
||||||
<Icon size={20} className={isActive ? "text-white" : "text-slate-500 group-hover:text-white"} />
|
<Icon size={20} className={isActive ? "text-white" : "text-slate-500 group-hover:text-white"} />
|
||||||
<span className="font-medium">{item.label}</span>
|
</div>
|
||||||
|
<span className="font-medium opacity-0 group-hover:opacity-100 transition-opacity duration-300 whitespace-nowrap overflow-hidden">
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className="p-4 border-t border-slate-800">
|
<div className="p-4 border-t border-slate-800">
|
||||||
<div className="flex items-center gap-3 px-4 py-3 rounded-lg bg-slate-800/50">
|
<div className="flex items-center gap-3 px-2 py-3 rounded-lg bg-slate-800/50 overflow-hidden whitespace-nowrap">
|
||||||
|
<div className="min-w-[32px]">
|
||||||
<UserButton afterSignOutUrl="/" />
|
<UserButton afterSignOutUrl="/" />
|
||||||
<div className="flex-1 min-w-0">
|
</div>
|
||||||
|
<div className="flex-1 min-w-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
<p className="text-sm font-medium text-white truncate">
|
<p className="text-sm font-medium text-white truncate">
|
||||||
{user?.fullName || "Admin User"}
|
{user?.fullName || "Admin User"}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,56 +1,49 @@
|
|||||||
import * as React from "react";
|
import React from 'react'
|
||||||
import { Slot } from "@radix-ui/react-slot";
|
import { cn } from '@/lib/utils'
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { Loader2 } from 'lucide-react'
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
|
variant?: 'primary' | 'secondary' | 'ghost' | 'destructive' | 'outline' | 'default'
|
||||||
const buttonVariants = cva(
|
size?: 'default' | 'sm' | 'lg' | 'icon'
|
||||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
isLoading?: boolean
|
||||||
{
|
children: React.ReactNode
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
||||||
destructive:
|
|
||||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
||||||
outline:
|
|
||||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
||||||
secondary:
|
|
||||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
default: "h-10 px-4 py-2",
|
|
||||||
sm: "h-9 rounded-md px-3",
|
|
||||||
lg: "h-11 rounded-md px-8",
|
|
||||||
icon: "h-10 w-10",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultVariants: {
|
|
||||||
variant: "default",
|
|
||||||
size: "default",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export interface ButtonProps
|
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
||||||
VariantProps<typeof buttonVariants> {
|
|
||||||
asChild?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
export function Button({
|
||||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
variant = 'primary',
|
||||||
const Comp = asChild ? Slot : "button";
|
size = 'default',
|
||||||
return (
|
isLoading = false,
|
||||||
<Comp
|
children,
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
className = '',
|
||||||
ref={ref}
|
disabled,
|
||||||
{...props}
|
...props
|
||||||
/>
|
}: ButtonProps) {
|
||||||
);
|
const baseClasses = 'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50'
|
||||||
},
|
|
||||||
);
|
|
||||||
Button.displayName = "Button";
|
|
||||||
|
|
||||||
export { Button, buttonVariants };
|
const variantClasses = {
|
||||||
|
primary: 'bg-blue-600 text-white hover:bg-blue-700 shadow hover:bg-blue-700/90',
|
||||||
|
default: 'bg-blue-600 text-white hover:bg-blue-700 shadow hover:bg-blue-700/90',
|
||||||
|
secondary: 'bg-slate-100 text-slate-900 hover:bg-slate-200/80',
|
||||||
|
ghost: 'hover:bg-slate-100 hover:text-slate-900',
|
||||||
|
destructive: 'bg-red-500 text-white hover:bg-red-600/90',
|
||||||
|
outline: 'border border-input bg-transparent shadow-sm hover:bg-slate-100 hover:text-slate-900'
|
||||||
|
}
|
||||||
|
|
||||||
|
const sizeClasses = {
|
||||||
|
default: 'h-9 px-4 py-2',
|
||||||
|
sm: 'h-8 rounded-md px-3 text-xs',
|
||||||
|
lg: 'h-10 rounded-md px-8',
|
||||||
|
icon: 'h-9 w-9'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={cn(baseClasses, variantClasses[variant], sizeClasses[size], className)}
|
||||||
|
disabled={disabled || isLoading}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardHeader, CardContent } from "@/components/ui/card";
|
import { Card, CardHeader, CardContent } from "@/components/ui/card";
|
||||||
|
|
||||||
interface Recommendation {
|
interface Recommendation {
|
||||||
id: string;
|
id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
type: "short_term" | "medium_term" | "long_term" | "ai_plan";
|
type: "short_term" | "medium_term" | "long_term" | "ai_plan";
|
||||||
content: string;
|
recommendationText: string;
|
||||||
activityPlan?: string;
|
activityPlan?: string;
|
||||||
dietPlan?: string;
|
dietPlan?: string;
|
||||||
status: "pending" | "completed" | "approved" | "rejected";
|
status: "pending" | "completed" | "approved" | "rejected";
|
||||||
@@ -97,7 +97,7 @@ export function Recommendations({ userId }: RecommendationsProps) {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<p className="text-sm font-medium">{rec.content}</p>
|
<p className="text-gray-700">{rec.recommendationText}</p>
|
||||||
{rec.type === 'ai_plan' && (
|
{rec.type === 'ai_plan' && (
|
||||||
<div className="mt-2 text-xs text-gray-600 space-y-1">
|
<div className="mt-2 text-xs text-gray-600 space-y-1">
|
||||||
{rec.activityPlan && <p><span className="font-semibold">Activity:</span> {rec.activityPlan}</p>}
|
{rec.activityPlan && <p><span className="font-semibold">Activity:</span> {rec.activityPlan}</p>}
|
||||||
|
|||||||
@@ -9,6 +9,19 @@ import { formatDate } from "@/lib/utils";
|
|||||||
|
|
||||||
ModuleRegistry.registerModules([AllCommunityModule]);
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
||||||
|
|
||||||
|
function getTimeAgo(date: Date): string {
|
||||||
|
const now = new Date();
|
||||||
|
const diffMs = now.getTime() - date.getTime();
|
||||||
|
const diffMins = Math.floor(diffMs / 60000);
|
||||||
|
const diffHours = Math.floor(diffMins / 60);
|
||||||
|
const diffDays = Math.floor(diffHours / 24);
|
||||||
|
|
||||||
|
if (diffMins < 1) return "just now";
|
||||||
|
if (diffMins < 60) return `${diffMins}m ago`;
|
||||||
|
if (diffHours < 24) return `${diffHours}h ago`;
|
||||||
|
return `${diffDays}d ago`;
|
||||||
|
}
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -16,7 +29,11 @@ interface User {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
role: string;
|
role: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
|
gymId?: string;
|
||||||
|
gymName?: string | null;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
isCheckedIn?: boolean;
|
||||||
|
checkInTime?: Date;
|
||||||
client?: {
|
client?: {
|
||||||
id: string;
|
id: string;
|
||||||
membershipType: string;
|
membershipType: string;
|
||||||
@@ -45,6 +62,31 @@ export function UserGrid({
|
|||||||
}: UserGridProps) {
|
}: UserGridProps) {
|
||||||
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
|
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
|
||||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||||
|
const [gymNames, setGymNames] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
let isMounted = true;
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/gyms");
|
||||||
|
const data = await res.json();
|
||||||
|
if (isMounted && Array.isArray(data)) {
|
||||||
|
const map: Record<string, string> = {};
|
||||||
|
for (const g of data) {
|
||||||
|
if (g && g.id) {
|
||||||
|
map[g.id] = g.name || g.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setGymNames(map);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// silently fail; we'll show gymId if name not available
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return () => {
|
||||||
|
isMounted = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const columnDefs: ColDef<User>[] = useMemo(
|
const columnDefs: ColDef<User>[] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@@ -79,16 +121,36 @@ export function UserGrid({
|
|||||||
roleColors[params.value as keyof typeof roleColors] ||
|
roleColors[params.value as keyof typeof roleColors] ||
|
||||||
"bg-gray-100 text-gray-800";
|
"bg-gray-100 text-gray-800";
|
||||||
|
|
||||||
const label = params.value === 'superAdmin' ? 'Super Admin' : params.value.charAt(0).toUpperCase() + params.value.slice(1);
|
const label =
|
||||||
|
params.value === "superAdmin"
|
||||||
|
? "Super Admin"
|
||||||
|
: params.value.charAt(0).toUpperCase() + params.value.slice(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${colorClass}`}>
|
<span
|
||||||
|
className={`px-2 py-1 rounded-full text-xs font-medium ${colorClass}`}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
headerName: "Gym",
|
||||||
|
field: "gymId",
|
||||||
|
filter: "agTextColumnFilter",
|
||||||
|
sortable: true,
|
||||||
|
minWidth: 160,
|
||||||
|
valueFormatter: (params: any) => {
|
||||||
|
const gymId = params.value;
|
||||||
|
const gymName = params.data?.gymName;
|
||||||
|
if (!gymId && !gymName) return "None";
|
||||||
|
if (gymName) return gymName;
|
||||||
|
return gymNames[gymId] || gymId;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
headerName: "Phone",
|
headerName: "Phone",
|
||||||
field: "phone",
|
field: "phone",
|
||||||
@@ -103,7 +165,8 @@ export function UserGrid({
|
|||||||
filter: "agTextColumnFilter",
|
filter: "agTextColumnFilter",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: (params: any) => {
|
cellRenderer: (params: any) => {
|
||||||
if (!params.value || params.value === "N/A") return <span className="text-gray-400">N/A</span>;
|
if (!params.value || params.value === "N/A")
|
||||||
|
return <span className="text-gray-400">N/A</span>;
|
||||||
|
|
||||||
const membershipColors = {
|
const membershipColors = {
|
||||||
vip: "bg-yellow-100 text-yellow-800 border-yellow-200",
|
vip: "bg-yellow-100 text-yellow-800 border-yellow-200",
|
||||||
@@ -114,10 +177,13 @@ export function UserGrid({
|
|||||||
membershipColors[params.value as keyof typeof membershipColors] ||
|
membershipColors[params.value as keyof typeof membershipColors] ||
|
||||||
"bg-gray-100 text-gray-800";
|
"bg-gray-100 text-gray-800";
|
||||||
|
|
||||||
const label = params.value.charAt(0).toUpperCase() + params.value.slice(1);
|
const label =
|
||||||
|
params.value.charAt(0).toUpperCase() + params.value.slice(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={`px-2 py-1 rounded-full text-xs font-medium border ${colorClass}`}>
|
<span
|
||||||
|
className={`px-2 py-1 rounded-full text-xs font-medium border ${colorClass}`}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@@ -130,7 +196,8 @@ export function UserGrid({
|
|||||||
filter: "agTextColumnFilter",
|
filter: "agTextColumnFilter",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: (params: any) => {
|
cellRenderer: (params: any) => {
|
||||||
if (!params.value || params.value === "N/A") return <span className="text-gray-400">N/A</span>;
|
if (!params.value || params.value === "N/A")
|
||||||
|
return <span className="text-gray-400">N/A</span>;
|
||||||
|
|
||||||
const statusColors = {
|
const statusColors = {
|
||||||
active: "bg-green-100 text-green-800",
|
active: "bg-green-100 text-green-800",
|
||||||
@@ -142,16 +209,42 @@ export function UserGrid({
|
|||||||
statusColors[params.value as keyof typeof statusColors] ||
|
statusColors[params.value as keyof typeof statusColors] ||
|
||||||
"bg-gray-100 text-gray-800";
|
"bg-gray-100 text-gray-800";
|
||||||
|
|
||||||
const label = params.value.charAt(0).toUpperCase() + params.value.slice(1);
|
const label =
|
||||||
|
params.value.charAt(0).toUpperCase() + params.value.slice(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${colorClass}`}>
|
<span
|
||||||
|
className={`px-2 py-1 rounded-full text-xs font-medium ${colorClass}`}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
headerName: "Currently Checked In",
|
||||||
|
valueGetter: (params) => params.data?.isCheckedIn,
|
||||||
|
filter: "agTextColumnFilter",
|
||||||
|
sortable: true,
|
||||||
|
cellRenderer: (params: any) => {
|
||||||
|
if (!params.data?.isCheckedIn) {
|
||||||
|
return <span className="text-gray-400">—</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkInTime = params.data.checkInTime
|
||||||
|
? new Date(params.data.checkInTime)
|
||||||
|
: null;
|
||||||
|
const timeAgo = checkInTime ? getTimeAgo(checkInTime) : "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 border border-green-200">
|
||||||
|
✓ Checked In {timeAgo && `(${timeAgo})`}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
minWidth: 180,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
headerName: "Join Date",
|
headerName: "Join Date",
|
||||||
valueGetter: (params) =>
|
valueGetter: (params) =>
|
||||||
@@ -187,14 +280,16 @@ export function UserGrid({
|
|||||||
const gridRef = React.useRef<AgGridReact<User>>(null);
|
const gridRef = React.useRef<AgGridReact<User>>(null);
|
||||||
|
|
||||||
const gridOptions = {
|
const gridOptions = {
|
||||||
theme: "legacy",
|
theme: "legacy" as const,
|
||||||
columnDefs,
|
columnDefs,
|
||||||
defaultColDef,
|
defaultColDef,
|
||||||
rowData: users,
|
rowData: users,
|
||||||
rowSelection: "multiple",
|
rowSelection: "multiple" as const,
|
||||||
onSelectionChanged: () => {
|
onSelectionChanged: () => {
|
||||||
const selectedNodes = gridRef.current?.api.getSelectedNodes();
|
const selectedNodes = gridRef.current?.api.getSelectedNodes();
|
||||||
const selectedData = selectedNodes?.map((node) => node.data) || [];
|
const selectedData =
|
||||||
|
selectedNodes?.map((node) => node.data).filter((u): u is User => !!u) ||
|
||||||
|
[];
|
||||||
setSelectedUsers(selectedData);
|
setSelectedUsers(selectedData);
|
||||||
if (selectedData.length === 1 && onUserSelect) {
|
if (selectedData.length === 1 && onUserSelect) {
|
||||||
onUserSelect(selectedData[0]);
|
onUserSelect(selectedData[0]);
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { UserGrid } from "@/components/users/UserGrid";
|
import { UserGrid } from "@/components/users/UserGrid";
|
||||||
import { Button } from "@/components/ui/Button";
|
// import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardHeader, CardContent } from "@/components/ui/card";
|
import { Card, CardHeader, CardContent } from "@/components/ui/card";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { useUser } from "@clerk/nextjs";
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -12,7 +14,13 @@ interface User {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
role: string;
|
role: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
|
gymId?: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
isCheckedIn?: boolean;
|
||||||
|
checkInTime?: Date;
|
||||||
|
lastCheckInTime?: Date;
|
||||||
|
checkInsThisWeek?: number;
|
||||||
|
checkInsThisMonth?: number;
|
||||||
client?: {
|
client?: {
|
||||||
id: string;
|
id: string;
|
||||||
membershipType: string;
|
membershipType: string;
|
||||||
@@ -23,6 +31,7 @@ interface User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function UserManagement() {
|
export function UserManagement() {
|
||||||
|
const { user } = useUser();
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [filter, setFilter] = useState<string>("all");
|
const [filter, setFilter] = useState<string>("all");
|
||||||
@@ -35,8 +44,32 @@ export function UserManagement() {
|
|||||||
email: string;
|
email: string;
|
||||||
role: string;
|
role: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
|
gymId: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
|
// Active gyms for dropdown
|
||||||
|
const [gyms, setGyms] = useState<Array<{ id: string; name: string }>>([]);
|
||||||
|
|
||||||
|
// Load gyms when modal opens or refreshes
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEditing) {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/gyms");
|
||||||
|
const data = await res.json();
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
// map down to id and name to avoid extra payload use here
|
||||||
|
setGyms(data.map((g: any) => ({ id: g.id, name: g.name })));
|
||||||
|
} else {
|
||||||
|
setGyms([]);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setGyms([]);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}, [isEditing]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUsers();
|
fetchUsers();
|
||||||
}, [filter]);
|
}, [filter]);
|
||||||
@@ -44,10 +77,33 @@ export function UserManagement() {
|
|||||||
const fetchUsers = async () => {
|
const fetchUsers = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const url = filter === "all" ? "/api/users" : `/api/users?role=${filter}`;
|
const ts = Date.now();
|
||||||
|
const url =
|
||||||
|
filter === "all"
|
||||||
|
? `/api/users?ts=${ts}`
|
||||||
|
: `/api/users?role=${filter}&ts=${ts}`;
|
||||||
|
|
||||||
const response = await fetch(url);
|
console.log("UserManagement.fetchUsers: fetching URL", url);
|
||||||
|
const response = await fetch(url, { cache: "no-store" });
|
||||||
|
console.log(
|
||||||
|
"UserManagement.fetchUsers: response.ok",
|
||||||
|
response.ok,
|
||||||
|
"status",
|
||||||
|
response.status,
|
||||||
|
);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
console.log(
|
||||||
|
"UserManagement.fetchUsers: received users count",
|
||||||
|
Array.isArray(data.users) ? data.users.length : 0,
|
||||||
|
"sample",
|
||||||
|
data.users && data.users[0]
|
||||||
|
? {
|
||||||
|
id: data.users[0].id,
|
||||||
|
gymId: data.users[0].gymId,
|
||||||
|
role: data.users[0].role,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
setUsers(data.users || []);
|
setUsers(data.users || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch users:", error);
|
console.error("Failed to fetch users:", error);
|
||||||
@@ -68,6 +124,7 @@ export function UserManagement() {
|
|||||||
email: user.email,
|
email: user.email,
|
||||||
role: user.role,
|
role: user.role,
|
||||||
phone: user.phone || "",
|
phone: user.phone || "",
|
||||||
|
gymId: user.gymId || "",
|
||||||
});
|
});
|
||||||
setIsEditing(true);
|
setIsEditing(true);
|
||||||
};
|
};
|
||||||
@@ -144,24 +201,92 @@ export function UserManagement() {
|
|||||||
try {
|
try {
|
||||||
if (selectedUser) {
|
if (selectedUser) {
|
||||||
// Update existing user
|
// Update existing user
|
||||||
|
console.log(
|
||||||
|
"UserManagement.handleSaveEdit: sending PUT /api/users payload",
|
||||||
|
{
|
||||||
|
id: selectedUser.id,
|
||||||
|
email: editForm.email,
|
||||||
|
firstName: editForm.firstName,
|
||||||
|
lastName: editForm.lastName,
|
||||||
|
role: editForm.role,
|
||||||
|
phone: editForm.phone,
|
||||||
|
gymId: editForm.gymId === "" ? null : editForm.gymId,
|
||||||
|
},
|
||||||
|
);
|
||||||
const response = await fetch("/api/users", {
|
const response = await fetch("/api/users", {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ id: selectedUser.id, ...editForm }),
|
body: JSON.stringify({
|
||||||
|
id: selectedUser.id,
|
||||||
|
email: editForm.email,
|
||||||
|
firstName: editForm.firstName,
|
||||||
|
lastName: editForm.lastName,
|
||||||
|
role: editForm.role,
|
||||||
|
phone: editForm.phone,
|
||||||
|
gymId: editForm.gymId === "" ? null : editForm.gymId,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
console.log(
|
||||||
|
"UserManagement.handleSaveEdit: PUT /api/users response.ok",
|
||||||
|
response.ok,
|
||||||
|
"status",
|
||||||
|
response.status,
|
||||||
|
);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
// Optimistically update local state so grid reflects changes immediately
|
||||||
|
setUsers((prev) =>
|
||||||
|
prev.map((u) =>
|
||||||
|
u.id === selectedUser.id
|
||||||
|
? {
|
||||||
|
...u,
|
||||||
|
email: editForm.email,
|
||||||
|
firstName: editForm.firstName,
|
||||||
|
lastName: editForm.lastName,
|
||||||
|
role: editForm.role,
|
||||||
|
phone: editForm.phone || undefined,
|
||||||
|
gymId: editForm.gymId === "" ? undefined : editForm.gymId,
|
||||||
|
}
|
||||||
|
: u,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setSelectedUser((prev) =>
|
||||||
|
prev
|
||||||
|
? {
|
||||||
|
...prev,
|
||||||
|
email: editForm.email,
|
||||||
|
firstName: editForm.firstName,
|
||||||
|
lastName: editForm.lastName,
|
||||||
|
role: editForm.role,
|
||||||
|
phone: editForm.phone || undefined,
|
||||||
|
gymId: editForm.gymId === "" ? undefined : editForm.gymId,
|
||||||
|
}
|
||||||
|
: prev,
|
||||||
|
);
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
setEditForm(null);
|
setEditForm(null);
|
||||||
|
// Still re-fetch from server to ensure consistency
|
||||||
|
console.log(
|
||||||
|
"UserManagement.handleSaveEdit: re-fetching users after successful edit",
|
||||||
|
);
|
||||||
fetchUsers();
|
fetchUsers();
|
||||||
} else {
|
} else {
|
||||||
|
const errText = await response.text().catch(() => "");
|
||||||
|
console.error("UserManagement.handleSaveEdit: update failed", {
|
||||||
|
status: response.status,
|
||||||
|
body: errText,
|
||||||
|
});
|
||||||
alert("Error updating user");
|
alert("Error updating user");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create (Invite) new user
|
// Create (Invite) new user
|
||||||
const response = await fetch("/api/users", {
|
const response = await fetch("/api/invitations", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(editForm),
|
body: JSON.stringify({
|
||||||
|
inviteeEmail: editForm.email,
|
||||||
|
roleAssigned: editForm.role,
|
||||||
|
gymId: editForm.gymId || undefined,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -205,20 +330,20 @@ export function UserManagement() {
|
|||||||
<h2 className="text-2xl font-bold">User Management</h2>
|
<h2 className="text-2xl font-bold">User Management</h2>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant={filter === "all" ? "primary" : "secondary"}
|
variant={filter === "all" ? "default" : "outline"}
|
||||||
onClick={() => setFilter("all")}
|
onClick={() => setFilter("all")}
|
||||||
>
|
>
|
||||||
All Users
|
All Users
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant={filter === "client" ? "default" : "outline"}
|
||||||
onClick={() => selectedUser && handleEditUser(selectedUser)}
|
onClick={() => selectedUser && handleEditUser(selectedUser)}
|
||||||
disabled={!selectedUser}
|
disabled={!selectedUser}
|
||||||
>
|
>
|
||||||
Edit User
|
Edit User
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant={filter === "client" ? "default" : "outline"}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setEditForm({
|
setEditForm({
|
||||||
firstName: "",
|
firstName: "",
|
||||||
@@ -226,6 +351,7 @@ export function UserManagement() {
|
|||||||
email: "",
|
email: "",
|
||||||
role: "client",
|
role: "client",
|
||||||
phone: "",
|
phone: "",
|
||||||
|
gymId: String((user?.publicMetadata as any)?.gymId ?? ""),
|
||||||
});
|
});
|
||||||
setSelectedUser(null);
|
setSelectedUser(null);
|
||||||
setIsEditing(true);
|
setIsEditing(true);
|
||||||
@@ -234,32 +360,32 @@ export function UserManagement() {
|
|||||||
Invite User
|
Invite User
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant={filter === "client" ? "default" : "outline"}
|
||||||
onClick={() => selectedUser && handleDeleteUser(selectedUser)}
|
onClick={() => selectedUser && handleDeleteUser(selectedUser)}
|
||||||
disabled={!selectedUser}
|
disabled={!selectedUser}
|
||||||
>
|
>
|
||||||
Delete User
|
Delete User
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={filter === "client" ? "primary" : "secondary"}
|
variant={filter === "client" ? "default" : "outline"}
|
||||||
onClick={() => setFilter("client")}
|
onClick={() => setFilter("client")}
|
||||||
>
|
>
|
||||||
Clients
|
Clientsa
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={filter === "trainer" ? "primary" : "secondary"}
|
variant={filter === "trainer" ? "default" : "outline"}
|
||||||
onClick={() => setFilter("trainer")}
|
onClick={() => setFilter("trainer")}
|
||||||
>
|
>
|
||||||
Trainers
|
Trainers
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={filter === "admin" ? "primary" : "secondary"}
|
variant={filter === "admin" ? "default" : "outline"}
|
||||||
onClick={() => setFilter("admin")}
|
onClick={() => setFilter("admin")}
|
||||||
>
|
>
|
||||||
Admins
|
Admins
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={filter === "superAdmin" ? "primary" : "secondary"}
|
variant={filter === "superAdmin" ? "default" : "outline"}
|
||||||
onClick={() => setFilter("superAdmin")}
|
onClick={() => setFilter("superAdmin")}
|
||||||
>
|
>
|
||||||
Super Admins
|
Super Admins
|
||||||
@@ -277,10 +403,10 @@ export function UserManagement() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button variant="secondary" onClick={handleRefresh}>
|
<Button variant="default" onClick={handleRefresh}>
|
||||||
Refresh
|
Refresh
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" onClick={handleExport}>
|
<Button variant="default" onClick={handleExport}>
|
||||||
Export CSV
|
Export CSV
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -302,7 +428,9 @@ export function UserManagement() {
|
|||||||
{isEditing && editForm && (
|
{isEditing && editForm && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
<div className="bg-white p-6 rounded-lg shadow-lg max-w-md w-full">
|
<div className="bg-white p-6 rounded-lg shadow-lg max-w-md w-full">
|
||||||
<h3 className="text-lg font-semibold mb-4">{selectedUser ? 'Edit User' : 'Invite New User'}</h3>
|
<h3 className="text-lg font-semibold mb-4">
|
||||||
|
{selectedUser ? "Edit User" : "Invite New User"}
|
||||||
|
</h3>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -383,6 +511,26 @@ export function UserManagement() {
|
|||||||
className="w-full border border-gray-300 rounded px-3 py-2"
|
className="w-full border border-gray-300 rounded px-3 py-2"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">Gym</label>
|
||||||
|
<select
|
||||||
|
value={editForm.gymId}
|
||||||
|
onChange={(e) =>
|
||||||
|
setEditForm({ ...editForm, gymId: e.target.value })
|
||||||
|
}
|
||||||
|
className="w-full border border-gray-300 rounded px-3 py-2"
|
||||||
|
>
|
||||||
|
<option value="">Proceed without gym</option>
|
||||||
|
{gyms.map((g) => (
|
||||||
|
<option key={g.id} value={g.id}>
|
||||||
|
{g.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<p className="text-xs text-gray-500 mt-1">
|
||||||
|
Select an active gym or proceed without a gym.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -398,7 +546,7 @@ export function UserManagement() {
|
|||||||
type="submit"
|
type="submit"
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||||
>
|
>
|
||||||
{selectedUser ? 'Save Changes' : 'Send Invitation'}
|
{selectedUser ? "Save Changes" : "Send Invitation"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -444,7 +592,7 @@ export function UserManagement() {
|
|||||||
</a>
|
</a>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium mb-2">Basic Information</h4>
|
<h4 className="font-medium mb-2">Basic Information</h4>
|
||||||
<div className="space-y-1 text-sm">
|
<div className="space-y-1 text-sm">
|
||||||
@@ -500,6 +648,26 @@ export function UserManagement() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4 className="font-medium mb-2">Check-In Statistics</h4>
|
||||||
|
<div className="space-y-1 text-sm">
|
||||||
|
<p>
|
||||||
|
<span className="font-medium">Last Check-In:</span>{" "}
|
||||||
|
{selectedUser.lastCheckInTime
|
||||||
|
? new Date(selectedUser.lastCheckInTime).toLocaleString()
|
||||||
|
: "Never"}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span className="font-medium">This Week:</span>{" "}
|
||||||
|
{selectedUser.checkInsThisWeek || 0} check-ins
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span className="font-medium">This Month:</span>{" "}
|
||||||
|
{selectedUser.checkInsThisMonth || 0} check-ins
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { getDatabase } from '@/lib/database';
|
||||||
|
import type { FitnessGoal, FitnessProfile, Recommendation } from '@/lib/database/types';
|
||||||
|
|
||||||
|
export interface AIContext {
|
||||||
|
profile: FitnessProfile;
|
||||||
|
activeGoals: FitnessGoal[];
|
||||||
|
completedGoals: FitnessGoal[];
|
||||||
|
recentRecommendations: Recommendation[];
|
||||||
|
progressSummary: {
|
||||||
|
goalsCompleted: number;
|
||||||
|
goalsActive: number;
|
||||||
|
averageProgress: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build comprehensive AI context for a user
|
||||||
|
* Aggregates fitness profile, goals, and recommendation history
|
||||||
|
*/
|
||||||
|
export async function buildAIContext(userId: string): Promise<AIContext> {
|
||||||
|
const db = await getDatabase();
|
||||||
|
|
||||||
|
// Fetch fitness profile
|
||||||
|
const profile = await db.getFitnessProfileByUserId(userId);
|
||||||
|
|
||||||
|
if (!profile) {
|
||||||
|
throw new Error(`Fitness profile not found for user ${userId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all fitness goals
|
||||||
|
const allGoals = await db.getFitnessGoalsByUserId(userId);
|
||||||
|
|
||||||
|
// Separate active and completed goals
|
||||||
|
const activeGoals = allGoals.filter((g) => g.status === 'active');
|
||||||
|
const completedGoals = allGoals.filter((g) => g.status === 'completed');
|
||||||
|
|
||||||
|
// Get all recommendations
|
||||||
|
const allRecommendations = await db.getRecommendationsByUserId(userId);
|
||||||
|
|
||||||
|
// Filter recent recommendations (last 7 days)
|
||||||
|
const sevenDaysAgo = new Date();
|
||||||
|
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
||||||
|
|
||||||
|
const recentRecommendations = allRecommendations
|
||||||
|
.filter((r) => new Date(r.createdAt) > sevenDaysAgo)
|
||||||
|
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
||||||
|
.slice(0, 5);
|
||||||
|
|
||||||
|
// Calculate progress summary
|
||||||
|
const progressSummary = {
|
||||||
|
goalsCompleted: completedGoals.length,
|
||||||
|
goalsActive: activeGoals.length,
|
||||||
|
averageProgress:
|
||||||
|
activeGoals.length > 0
|
||||||
|
? activeGoals.reduce((sum, g) => sum + (g.progress || 0), 0) / activeGoals.length
|
||||||
|
: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
profile,
|
||||||
|
activeGoals,
|
||||||
|
completedGoals,
|
||||||
|
recentRecommendations,
|
||||||
|
progressSummary,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format goal for display in AI prompt
|
||||||
|
*/
|
||||||
|
export function formatGoalForPrompt(goal: FitnessGoal): string {
|
||||||
|
const progress = goal.progress || 0;
|
||||||
|
const current = goal.currentValue || 0;
|
||||||
|
const target = goal.targetValue;
|
||||||
|
const unit = goal.unit || '';
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
return `${goal.title}: ${current}/${target} ${unit} (${progress.toFixed(1)}% complete)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${goal.title}: ${progress.toFixed(1)}% complete`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import type { AIContext } from './ai-context';
|
||||||
|
import { formatGoalForPrompt } from './ai-context';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build enhanced AI prompt with comprehensive user context
|
||||||
|
* Includes profile, goals, progress, and recommendation history
|
||||||
|
*/
|
||||||
|
export function buildEnhancedPrompt(context: AIContext): string {
|
||||||
|
const { profile, activeGoals, completedGoals, recentRecommendations, progressSummary } = context;
|
||||||
|
|
||||||
|
// Build goals section
|
||||||
|
const activeGoalsText =
|
||||||
|
activeGoals.length > 0
|
||||||
|
? activeGoals.map((g) => `- ${formatGoalForPrompt(g)}`).join('\n')
|
||||||
|
: '- No active goals set';
|
||||||
|
|
||||||
|
const completedGoalsText =
|
||||||
|
completedGoals.length > 0
|
||||||
|
? completedGoals.slice(0, 3).map((g) => g.title).join(', ')
|
||||||
|
: 'None yet';
|
||||||
|
|
||||||
|
// Build context about recent recommendations
|
||||||
|
const recommendationContextText =
|
||||||
|
recentRecommendations.length > 0
|
||||||
|
? `The user has received ${recentRecommendations.length} recommendations in the past week. Consider their progress and avoid repetitive advice.`
|
||||||
|
: 'This is a new user or they haven\'t received recent recommendations. Provide comprehensive guidance.';
|
||||||
|
|
||||||
|
return `You are a professional fitness trainer and nutritionist with access to the user's complete fitness journey.
|
||||||
|
|
||||||
|
## User Profile
|
||||||
|
- Height: ${profile.height || 'Not specified'} cm
|
||||||
|
- Weight: ${profile.weight || 'Not specified'} kg
|
||||||
|
- Age: ${profile.age || 'Not specified'}
|
||||||
|
- Gender: ${profile.gender || 'Not specified'}
|
||||||
|
- Primary Goal: ${profile.fitnessGoals?.[0] || 'General fitness'}
|
||||||
|
- Activity Level: ${profile.activityLevel || 'Not specified'}
|
||||||
|
- Medical Conditions: ${profile.medicalConditions || 'None'}
|
||||||
|
- Allergies: ${profile.allergies || 'None'}
|
||||||
|
- Injuries: ${profile.injuries || 'None'}
|
||||||
|
|
||||||
|
## Active Goals (${activeGoals.length})
|
||||||
|
${activeGoalsText}
|
||||||
|
|
||||||
|
## Recent Progress
|
||||||
|
- Goals Completed: ${progressSummary.goalsCompleted}
|
||||||
|
- Active Goals: ${progressSummary.goalsActive}
|
||||||
|
- Average Progress on Active Goals: ${progressSummary.averageProgress.toFixed(1)}%
|
||||||
|
${completedGoals.length > 0 ? `- Recently Completed: ${completedGoalsText}` : ''}
|
||||||
|
|
||||||
|
## Recommendation History
|
||||||
|
${recommendationContextText}
|
||||||
|
|
||||||
|
## Task
|
||||||
|
Generate a personalized daily recommendation that:
|
||||||
|
1. Acknowledges their progress on active goals
|
||||||
|
2. Provides specific, actionable steps toward goal completion
|
||||||
|
3. Builds on previous recommendations without being repetitive
|
||||||
|
4. Adapts to their current progress level
|
||||||
|
5. Takes into account their medical conditions, allergies, and injuries
|
||||||
|
|
||||||
|
Respond in the following JSON format ONLY, no other text. Do not use markdown formatting or code blocks:
|
||||||
|
{
|
||||||
|
"recommendationText": "Personalized motivation and progress acknowledgment (2-3 sentences)",
|
||||||
|
"activityPlan": "Specific workout plan aligned with active goals (detailed, 3-5 exercises or activities)",
|
||||||
|
"dietPlan": "Nutrition plan supporting their goals and restrictions (detailed, include meals and portions)"
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build basic prompt for users without complete context
|
||||||
|
* Fallback when goals or other data is missing
|
||||||
|
*/
|
||||||
|
export function buildBasicPrompt(profile: any): string {
|
||||||
|
return `You are a professional fitness trainer and nutritionist.
|
||||||
|
Generate a detailed daily recommendation for a user with the following profile:
|
||||||
|
- Height: ${profile.height} cm
|
||||||
|
- Weight: ${profile.weight} kg
|
||||||
|
- Age: ${profile.age}
|
||||||
|
- Gender: ${profile.gender}
|
||||||
|
- Goal: ${profile.fitnessGoals?.[0]}
|
||||||
|
- Activity Level: ${profile.activityLevel}
|
||||||
|
- Medical Conditions: ${profile.medicalConditions || "None"}
|
||||||
|
- Injuries: ${profile.injuries || "None"}
|
||||||
|
|
||||||
|
Please provide the response in the following JSON format ONLY, no other text. Do not use markdown formatting or code blocks:
|
||||||
|
{
|
||||||
|
"recommendationText": "General advice and motivation for today.",
|
||||||
|
"activityPlan": "Detailed workout or activity plan for today.",
|
||||||
|
"dietPlan": "Detailed meal plan for today."
|
||||||
|
}`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
* @jest-environment node
|
||||||
|
*/
|
||||||
|
import { DrizzleDatabase } from '../drizzle'
|
||||||
|
import { DatabaseConfig } from '../types'
|
||||||
|
import Database from 'better-sqlite3'
|
||||||
|
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
||||||
|
import * as schema from '@fitai/database'
|
||||||
|
|
||||||
|
describe('DrizzleDatabase', () => {
|
||||||
|
let db: DrizzleDatabase
|
||||||
|
let sqlite: Database.Database
|
||||||
|
let drizzleDb: ReturnType<typeof drizzle>
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
// Create in-memory SQLite database
|
||||||
|
sqlite = new Database(':memory:')
|
||||||
|
drizzleDb = drizzle(sqlite, { schema })
|
||||||
|
|
||||||
|
const config: DatabaseConfig = {
|
||||||
|
type: 'sqlite',
|
||||||
|
connection: { filename: ':memory:' },
|
||||||
|
options: { logging: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize DrizzleDatabase with the in-memory db
|
||||||
|
db = new DrizzleDatabase(config, drizzleDb as any)
|
||||||
|
await db.connect()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.disconnect()
|
||||||
|
sqlite.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('User Operations', () => {
|
||||||
|
it('should create and retrieve a user', async () => {
|
||||||
|
const newUser = {
|
||||||
|
email: 'test@example.com',
|
||||||
|
firstName: 'Test',
|
||||||
|
lastName: 'User',
|
||||||
|
password: 'password123',
|
||||||
|
role: 'client' as const
|
||||||
|
}
|
||||||
|
|
||||||
|
const createdUser = await db.createUser(newUser)
|
||||||
|
expect(createdUser).toBeDefined()
|
||||||
|
expect(createdUser.id).toBeDefined()
|
||||||
|
expect(createdUser.email).toBe(newUser.email)
|
||||||
|
|
||||||
|
const fetchedUser = await db.getUserById(createdUser.id)
|
||||||
|
expect(fetchedUser).toBeDefined()
|
||||||
|
expect(fetchedUser?.id).toBe(createdUser.id)
|
||||||
|
expect(fetchedUser?.email).toBe(createdUser.email)
|
||||||
|
// SQLite/Drizzle might truncate ms or handle dates differently in test env
|
||||||
|
expect(new Date(fetchedUser!.createdAt).getTime()).toBeLessThanOrEqual(createdUser.createdAt.getTime())
|
||||||
|
expect(new Date(fetchedUser!.updatedAt).getTime()).toBeLessThanOrEqual(createdUser.updatedAt.getTime())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should update a user', async () => {
|
||||||
|
const user = await db.createUser({
|
||||||
|
email: 'update@example.com',
|
||||||
|
firstName: 'Update',
|
||||||
|
lastName: 'Me',
|
||||||
|
password: 'password',
|
||||||
|
role: 'client'
|
||||||
|
})
|
||||||
|
|
||||||
|
const updated = await db.updateUser(user.id, { firstName: 'Updated' })
|
||||||
|
expect(updated?.firstName).toBe('Updated')
|
||||||
|
|
||||||
|
const fetched = await db.getUserById(user.id)
|
||||||
|
expect(fetched?.firstName).toBe('Updated')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should delete a user', async () => {
|
||||||
|
const user = await db.createUser({
|
||||||
|
email: 'delete@example.com',
|
||||||
|
firstName: 'Delete',
|
||||||
|
lastName: 'Me',
|
||||||
|
password: 'password',
|
||||||
|
role: 'client'
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleted = await db.deleteUser(user.id)
|
||||||
|
expect(deleted).toBe(true)
|
||||||
|
|
||||||
|
const fetched = await db.getUserById(user.id)
|
||||||
|
expect(fetched).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Client Operations', () => {
|
||||||
|
it('should create and retrieve a client', async () => {
|
||||||
|
const user = await db.createUser({
|
||||||
|
email: 'client@example.com',
|
||||||
|
firstName: 'Client',
|
||||||
|
lastName: 'User',
|
||||||
|
password: 'password',
|
||||||
|
role: 'client'
|
||||||
|
})
|
||||||
|
|
||||||
|
const newClient = {
|
||||||
|
userId: user.id,
|
||||||
|
membershipType: 'basic' as const,
|
||||||
|
membershipStatus: 'active' as const,
|
||||||
|
joinDate: new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
const createdClient = await db.createClient(newClient)
|
||||||
|
expect(createdClient).toBeDefined()
|
||||||
|
expect(createdClient.userId).toBe(user.id)
|
||||||
|
|
||||||
|
const fetchedClient = await db.getClientById(createdClient.id)
|
||||||
|
expect(fetchedClient).toBeDefined()
|
||||||
|
expect(fetchedClient?.id).toBe(createdClient.id)
|
||||||
|
expect(fetchedClient?.userId).toBe(createdClient.userId)
|
||||||
|
expect(fetchedClient?.membershipType).toBe(createdClient.membershipType)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Fitness Profile Operations', () => {
|
||||||
|
it('should create and retrieve a fitness profile', async () => {
|
||||||
|
const user = await db.createUser({
|
||||||
|
email: 'profile@example.com',
|
||||||
|
firstName: 'Profile',
|
||||||
|
lastName: 'User',
|
||||||
|
password: 'password',
|
||||||
|
role: 'client'
|
||||||
|
})
|
||||||
|
|
||||||
|
const newProfile = {
|
||||||
|
userId: user.id,
|
||||||
|
height: 180,
|
||||||
|
weight: 75,
|
||||||
|
age: 30,
|
||||||
|
gender: 'male' as const,
|
||||||
|
activityLevel: 'moderately_active' as const,
|
||||||
|
fitnessGoals: ['weight_loss'],
|
||||||
|
exerciseHabits: 'None',
|
||||||
|
dietHabits: 'None',
|
||||||
|
medicalConditions: 'None'
|
||||||
|
}
|
||||||
|
|
||||||
|
const createdProfile = await db.createFitnessProfile(newProfile as any)
|
||||||
|
expect(createdProfile).toBeDefined()
|
||||||
|
expect(createdProfile.userId).toBe(user.id)
|
||||||
|
|
||||||
|
const fetchedProfile = await db.getFitnessProfileByUserId(user.id)
|
||||||
|
expect(fetchedProfile).toBeDefined()
|
||||||
|
expect(fetchedProfile?.userId).toBe(user.id)
|
||||||
|
expect(fetchedProfile?.fitnessGoals).toEqual(expect.arrayContaining(['weight_loss']))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Attendance Operations', () => {
|
||||||
|
it('should check in and check out', async () => {
|
||||||
|
const user = await db.createUser({
|
||||||
|
email: 'attendance@example.com',
|
||||||
|
firstName: 'Attendance',
|
||||||
|
lastName: 'User',
|
||||||
|
password: 'password',
|
||||||
|
role: 'client'
|
||||||
|
})
|
||||||
|
|
||||||
|
const checkIn = await db.checkIn(user.id, 'gym')
|
||||||
|
expect(checkIn).toBeDefined()
|
||||||
|
expect(checkIn.checkOutTime).toBeUndefined()
|
||||||
|
|
||||||
|
const activeCheckIn = await db.getActiveCheckIn(user.id)
|
||||||
|
expect(activeCheckIn).toBeDefined()
|
||||||
|
expect(activeCheckIn?.id).toBe(checkIn.id)
|
||||||
|
|
||||||
|
const checkOut = await db.checkOut(checkIn.id)
|
||||||
|
expect(checkOut?.checkOutTime).toBeDefined()
|
||||||
|
|
||||||
|
const activeCheckInAfter = await db.getActiveCheckIn(user.id)
|
||||||
|
expect(activeCheckInAfter).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,720 @@
|
|||||||
|
import {
|
||||||
|
IDatabase,
|
||||||
|
User,
|
||||||
|
Client,
|
||||||
|
FitnessProfile,
|
||||||
|
Attendance,
|
||||||
|
Recommendation,
|
||||||
|
FitnessGoal,
|
||||||
|
DatabaseConfig,
|
||||||
|
} from "./types";
|
||||||
|
import {
|
||||||
|
db as defaultDb,
|
||||||
|
users,
|
||||||
|
clients,
|
||||||
|
fitnessProfiles,
|
||||||
|
attendance,
|
||||||
|
recommendations,
|
||||||
|
fitnessGoals,
|
||||||
|
eq,
|
||||||
|
and,
|
||||||
|
desc,
|
||||||
|
sql,
|
||||||
|
} from "@fitai/database";
|
||||||
|
import { InferSelectModel } from "drizzle-orm";
|
||||||
|
|
||||||
|
export class DrizzleDatabase implements IDatabase {
|
||||||
|
private config: DatabaseConfig;
|
||||||
|
private db: typeof defaultDb;
|
||||||
|
|
||||||
|
constructor(config: DatabaseConfig, db?: typeof defaultDb) {
|
||||||
|
this.config = config;
|
||||||
|
this.db = db || defaultDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(): Promise<void> {
|
||||||
|
// Drizzle with better-sqlite3 connects synchronously on initialization
|
||||||
|
// We can just log here if needed
|
||||||
|
if (this.config.options?.logging) {
|
||||||
|
console.log("Drizzle database connected");
|
||||||
|
}
|
||||||
|
await this.createTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(): Promise<void> {
|
||||||
|
// better-sqlite3 handle is managed by Drizzle, usually no explicit disconnect needed for connection pooling
|
||||||
|
// but we can close the underlying sqlite instance if we had access to it.
|
||||||
|
// For now, we'll assume it's handled.
|
||||||
|
if (this.config.options?.logging) {
|
||||||
|
console.log("Drizzle database disconnected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createTables(): Promise<void> {
|
||||||
|
// Users table
|
||||||
|
await this.db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
email TEXT UNIQUE NOT NULL,
|
||||||
|
first_name TEXT NOT NULL,
|
||||||
|
last_name TEXT NOT NULL,
|
||||||
|
password TEXT,
|
||||||
|
phone TEXT,
|
||||||
|
role TEXT NOT NULL CHECK (role IN ('superAdmin', 'admin', 'trainer', 'client')),
|
||||||
|
gym_id TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Migration: ensure gym_id column exists on users (for existing DBs)
|
||||||
|
const userCols = await this.db.all(sql`PRAGMA table_info('users')`);
|
||||||
|
if (!userCols.some((c: any) => c.name === "gym_id")) {
|
||||||
|
await this.db.run(sql`ALTER TABLE users ADD COLUMN gym_id TEXT`);
|
||||||
|
}
|
||||||
|
// Clients table
|
||||||
|
await this.db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS clients (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
membership_type TEXT NOT NULL CHECK (membership_type IN ('basic', 'premium', 'vip')),
|
||||||
|
membership_status TEXT NOT NULL CHECK (membership_status IN ('active', 'inactive', 'suspended')),
|
||||||
|
join_date INTEGER NOT NULL,
|
||||||
|
last_visit INTEGER,
|
||||||
|
emergency_contact_name TEXT,
|
||||||
|
emergency_contact_phone TEXT,
|
||||||
|
emergency_contact_relationship TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Fitness profiles table
|
||||||
|
await this.db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS fitness_profiles (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT NOT NULL UNIQUE,
|
||||||
|
height REAL,
|
||||||
|
weight REAL,
|
||||||
|
age INTEGER,
|
||||||
|
gender TEXT CHECK (gender IN ('male', 'female', 'other', 'prefer_not_to_say')),
|
||||||
|
activity_level TEXT CHECK (activity_level IN ('sedentary', 'lightly_active', 'moderately_active', 'very_active', 'extremely_active')),
|
||||||
|
fitness_goals TEXT,
|
||||||
|
exercise_habits TEXT,
|
||||||
|
diet_habits TEXT,
|
||||||
|
medical_conditions TEXT,
|
||||||
|
allergies TEXT,
|
||||||
|
injuries TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Attendance table
|
||||||
|
await this.db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS attendance (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
check_in_time INTEGER NOT NULL,
|
||||||
|
check_out_time INTEGER,
|
||||||
|
type TEXT NOT NULL CHECK (type IN ('gym', 'class', 'personal_training')),
|
||||||
|
notes TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Recommendations table
|
||||||
|
await this.db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS recommendations (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
fitness_profile_id TEXT NOT NULL,
|
||||||
|
recommendation_text TEXT NOT NULL,
|
||||||
|
activity_plan TEXT NOT NULL,
|
||||||
|
diet_plan TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL CHECK (status IN ('pending', 'approved', 'rejected')) DEFAULT 'pending',
|
||||||
|
generated_at INTEGER NOT NULL,
|
||||||
|
approved_at INTEGER,
|
||||||
|
approved_by TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (fitness_profile_id) REFERENCES fitness_profiles (id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Fitness Goals table
|
||||||
|
await this.db.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS fitness_goals (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
fitness_profile_id TEXT,
|
||||||
|
goal_type TEXT NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
target_value REAL,
|
||||||
|
current_value REAL,
|
||||||
|
unit TEXT,
|
||||||
|
start_date INTEGER NOT NULL,
|
||||||
|
target_date INTEGER,
|
||||||
|
completed_date INTEGER,
|
||||||
|
status TEXT NOT NULL DEFAULT 'active',
|
||||||
|
progress REAL DEFAULT 0,
|
||||||
|
priority TEXT DEFAULT 'medium',
|
||||||
|
notes TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (fitness_profile_id) REFERENCES fitness_profiles (id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// User operations
|
||||||
|
async createUser(
|
||||||
|
userData: Omit<User, "createdAt" | "updatedAt" | "id"> & { id?: string },
|
||||||
|
): Promise<User> {
|
||||||
|
const id = userData.id || Math.random().toString(36).substr(2, 9);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
const newUser = {
|
||||||
|
...userData,
|
||||||
|
id,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.db.insert(users).values(newUser);
|
||||||
|
return newUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserById(id: string): Promise<User | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.id, id))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapUser(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserByEmail(email: string): Promise<User | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.email, email))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapUser(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllUsers(): Promise<User[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.orderBy(desc(users.createdAt))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateUser(id: string, updates: Partial<User>): Promise<User | null> {
|
||||||
|
const { id: _, ...updateData } = updates;
|
||||||
|
if (Object.keys(updateData).length === 0) return this.getUserById(id);
|
||||||
|
|
||||||
|
await this.db
|
||||||
|
.update(users)
|
||||||
|
.set({ ...updateData, updatedAt: new Date() })
|
||||||
|
.where(eq(users.id, id))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getUserById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteUser(id: string): Promise<boolean> {
|
||||||
|
const result = await this.db.delete(users).where(eq(users.id, id)).run();
|
||||||
|
return result.changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async migrateUserId(oldId: string, newId: string): Promise<void> {
|
||||||
|
await this.db
|
||||||
|
.update(users)
|
||||||
|
.set({ id: newId })
|
||||||
|
.where(eq(users.id, oldId))
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client operations
|
||||||
|
async createClient(clientData: Omit<Client, "id">): Promise<Client> {
|
||||||
|
const id = Math.random().toString(36).substr(2, 9);
|
||||||
|
const newClient = {
|
||||||
|
id,
|
||||||
|
...clientData,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.db.insert(clients).values(newClient as any);
|
||||||
|
return this.mapClient(newClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getClientById(id: string): Promise<Client | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(clients)
|
||||||
|
.where(eq(clients.id, id))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapClient(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getClientByUserId(userId: string): Promise<Client | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(clients)
|
||||||
|
.where(eq(clients.userId, userId))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapClient(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllClients(): Promise<Client[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(clients)
|
||||||
|
.orderBy(desc(clients.joinDate))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateClient(
|
||||||
|
id: string,
|
||||||
|
updates: Partial<Client>,
|
||||||
|
): Promise<Client | null> {
|
||||||
|
const { id: _, ...updateData } = updates;
|
||||||
|
if (Object.keys(updateData).length === 0) return this.getClientById(id);
|
||||||
|
|
||||||
|
await this.db
|
||||||
|
.update(clients)
|
||||||
|
.set({ ...updateData, updatedAt: new Date() } as any)
|
||||||
|
.where(eq(clients.id, id))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getClientById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteClient(id: string): Promise<boolean> {
|
||||||
|
const result = await this.db
|
||||||
|
.delete(clients)
|
||||||
|
.where(eq(clients.id, id))
|
||||||
|
.run();
|
||||||
|
return result.changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fitness Profile operations
|
||||||
|
async createFitnessProfile(
|
||||||
|
profileData: Omit<FitnessProfile, "id" | "createdAt" | "updatedAt">,
|
||||||
|
): Promise<FitnessProfile> {
|
||||||
|
const now = new Date();
|
||||||
|
const id = Math.random().toString(36).substr(2, 9);
|
||||||
|
const newProfile = {
|
||||||
|
id,
|
||||||
|
...profileData,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.db.insert(fitnessProfiles).values(newProfile as any);
|
||||||
|
return { id, ...profileData, createdAt: now, updatedAt: now };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFitnessProfileByUserId(
|
||||||
|
userId: string,
|
||||||
|
): Promise<FitnessProfile | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(fitnessProfiles)
|
||||||
|
.where(eq(fitnessProfiles.userId, userId))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapFitnessProfile(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllFitnessProfiles(): Promise<FitnessProfile[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(fitnessProfiles)
|
||||||
|
.orderBy(desc(fitnessProfiles.createdAt))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapFitnessProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateFitnessProfile(
|
||||||
|
userId: string,
|
||||||
|
updates: Partial<FitnessProfile>,
|
||||||
|
): Promise<FitnessProfile | null> {
|
||||||
|
const { userId: _, ...updateData } = updates;
|
||||||
|
if (Object.keys(updateData).length === 0)
|
||||||
|
return this.getFitnessProfileByUserId(userId);
|
||||||
|
|
||||||
|
const dbUpdates = { ...updateData } as any;
|
||||||
|
if (updateData.fitnessGoals) {
|
||||||
|
dbUpdates.fitnessGoals = JSON.stringify(updateData.fitnessGoals);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.db
|
||||||
|
.update(fitnessProfiles)
|
||||||
|
.set({ ...dbUpdates, updatedAt: new Date() })
|
||||||
|
.where(eq(fitnessProfiles.userId, userId))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getFitnessProfileByUserId(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteFitnessProfile(userId: string): Promise<boolean> {
|
||||||
|
const result = await this.db
|
||||||
|
.delete(fitnessProfiles)
|
||||||
|
.where(eq(fitnessProfiles.userId, userId))
|
||||||
|
.run();
|
||||||
|
return result.changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attendance operations
|
||||||
|
async checkIn(
|
||||||
|
userId: string,
|
||||||
|
type: "gym" | "class" | "personal_training",
|
||||||
|
notes?: string,
|
||||||
|
): Promise<Attendance> {
|
||||||
|
const id = Math.random().toString(36).substr(2, 9);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
const newAttendance = {
|
||||||
|
id,
|
||||||
|
userId,
|
||||||
|
checkInTime: now,
|
||||||
|
type,
|
||||||
|
notes,
|
||||||
|
createdAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.db.insert(attendance).values(newAttendance as any);
|
||||||
|
|
||||||
|
// Update client last visit
|
||||||
|
const client = await this.getClientByUserId(userId);
|
||||||
|
if (client) {
|
||||||
|
await this.updateClient(client.id, { lastVisit: now });
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAttendance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkOut(attendanceId: string): Promise<Attendance | null> {
|
||||||
|
const now = new Date();
|
||||||
|
await this.db
|
||||||
|
.update(attendance)
|
||||||
|
.set({ checkOutTime: now })
|
||||||
|
.where(eq(attendance.id, attendanceId))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getAttendanceById(attendanceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAttendanceById(id: string): Promise<Attendance | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(attendance)
|
||||||
|
.where(eq(attendance.id, id))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapAttendance(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAttendanceHistory(userId: string): Promise<Attendance[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(attendance)
|
||||||
|
.where(eq(attendance.userId, userId))
|
||||||
|
.orderBy(desc(attendance.checkInTime))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapAttendance);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllAttendance(): Promise<Attendance[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(attendance)
|
||||||
|
.orderBy(desc(attendance.checkInTime))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapAttendance);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getActiveCheckIn(userId: string): Promise<Attendance | null> {
|
||||||
|
// Drizzle doesn't support IS NULL in where directly with simple syntax sometimes, but eq(col, null) works or isNull(col)
|
||||||
|
// We need to check how to filter for null checkOutTime.
|
||||||
|
// In Drizzle, we can filter in JS or use isNull operator if imported.
|
||||||
|
// Let's fetch recent and filter for now to be safe, or use raw sql if needed, but better to use Drizzle operators.
|
||||||
|
// Actually, we can just fetch all for user and filter in memory since it's unlikely to be huge for active checkins,
|
||||||
|
// but correct way is `isNull(attendance.checkOutTime)`.
|
||||||
|
// Since I didn't import `isNull`, I'll fetch recent history and find first active.
|
||||||
|
|
||||||
|
const history = await this.getAttendanceHistory(userId);
|
||||||
|
return history.find((a) => !a.checkOutTime) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recommendation operations
|
||||||
|
async createRecommendation(
|
||||||
|
data: Omit<Recommendation, "createdAt" | "approvedAt" | "approvedBy">,
|
||||||
|
): Promise<Recommendation> {
|
||||||
|
const now = new Date();
|
||||||
|
const newRec = {
|
||||||
|
...data,
|
||||||
|
createdAt: now,
|
||||||
|
status: data.status || "pending",
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.db.insert(recommendations).values(newRec as any);
|
||||||
|
return newRec as Recommendation;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRecommendationsByUserId(userId: string): Promise<Recommendation[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(recommendations)
|
||||||
|
.where(eq(recommendations.userId, userId))
|
||||||
|
.orderBy(desc(recommendations.createdAt))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapRecommendation);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllRecommendations(): Promise<Recommendation[]> {
|
||||||
|
const results = await this.db
|
||||||
|
.select()
|
||||||
|
.from(recommendations)
|
||||||
|
.orderBy(desc(recommendations.createdAt))
|
||||||
|
.all();
|
||||||
|
return results.map(this.mapRecommendation);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateRecommendation(
|
||||||
|
id: string,
|
||||||
|
updates: Partial<Recommendation>,
|
||||||
|
): Promise<Recommendation | null> {
|
||||||
|
const { id: _, ...updateData } = updates;
|
||||||
|
if (Object.keys(updateData).length === 0)
|
||||||
|
return this.getRecommendationById(id);
|
||||||
|
|
||||||
|
await this.db
|
||||||
|
.update(recommendations)
|
||||||
|
.set(updateData as any)
|
||||||
|
.where(eq(recommendations.id, id))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getRecommendationById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteRecommendation(id: string): Promise<boolean> {
|
||||||
|
const result = await this.db
|
||||||
|
.delete(recommendations)
|
||||||
|
.where(eq(recommendations.id, id))
|
||||||
|
.run();
|
||||||
|
return result.changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRecommendationById(id: string): Promise<Recommendation | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(recommendations)
|
||||||
|
.where(eq(recommendations.id, id))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapRecommendation(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fitness Goals operations
|
||||||
|
async createFitnessGoal(
|
||||||
|
goalData: Omit<FitnessGoal, "createdAt" | "updatedAt">,
|
||||||
|
): Promise<FitnessGoal> {
|
||||||
|
const now = new Date();
|
||||||
|
const newGoal = {
|
||||||
|
...goalData,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.db.insert(fitnessGoals).values(newGoal as any);
|
||||||
|
return newGoal as FitnessGoal;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFitnessGoalById(id: string): Promise<FitnessGoal | null> {
|
||||||
|
const result = await this.db
|
||||||
|
.select()
|
||||||
|
.from(fitnessGoals)
|
||||||
|
.where(eq(fitnessGoals.id, id))
|
||||||
|
.get();
|
||||||
|
return result ? this.mapFitnessGoal(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFitnessGoalsByUserId(
|
||||||
|
userId: string,
|
||||||
|
status?: string,
|
||||||
|
): Promise<FitnessGoal[]> {
|
||||||
|
let query = this.db
|
||||||
|
.select()
|
||||||
|
.from(fitnessGoals)
|
||||||
|
.where(eq(fitnessGoals.userId, userId));
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
query = this.db
|
||||||
|
.select()
|
||||||
|
.from(fitnessGoals)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(fitnessGoals.userId, userId),
|
||||||
|
eq(fitnessGoals.status, status as any),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await query.orderBy(desc(fitnessGoals.createdAt)).all();
|
||||||
|
return results.map(this.mapFitnessGoal);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateFitnessGoal(
|
||||||
|
id: string,
|
||||||
|
updates: Partial<FitnessGoal>,
|
||||||
|
): Promise<FitnessGoal | null> {
|
||||||
|
const { id: _, ...updateData } = updates;
|
||||||
|
if (Object.keys(updateData).length === 0)
|
||||||
|
return this.getFitnessGoalById(id);
|
||||||
|
|
||||||
|
await this.db
|
||||||
|
.update(fitnessGoals)
|
||||||
|
.set({ ...updateData, updatedAt: new Date() } as any)
|
||||||
|
.where(eq(fitnessGoals.id, id))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getFitnessGoalById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteFitnessGoal(id: string): Promise<boolean> {
|
||||||
|
const result = await this.db
|
||||||
|
.delete(fitnessGoals)
|
||||||
|
.where(eq(fitnessGoals.id, id))
|
||||||
|
.run();
|
||||||
|
return result.changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateGoalProgress(
|
||||||
|
id: string,
|
||||||
|
currentValue: number,
|
||||||
|
): Promise<FitnessGoal | null> {
|
||||||
|
const goal = await this.getFitnessGoalById(id);
|
||||||
|
if (!goal) return null;
|
||||||
|
|
||||||
|
let progress = goal.progress;
|
||||||
|
if (goal.targetValue && goal.targetValue > 0) {
|
||||||
|
progress = Math.min(100, (currentValue / goal.targetValue) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.db
|
||||||
|
.update(fitnessGoals)
|
||||||
|
.set({ currentValue, progress, updatedAt: new Date() })
|
||||||
|
.where(eq(fitnessGoals.id, id))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getFitnessGoalById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async completeGoal(id: string): Promise<FitnessGoal | null> {
|
||||||
|
const now = new Date();
|
||||||
|
await this.db
|
||||||
|
.update(fitnessGoals)
|
||||||
|
.set({
|
||||||
|
status: "completed",
|
||||||
|
progress: 100,
|
||||||
|
completedDate: now,
|
||||||
|
updatedAt: now,
|
||||||
|
})
|
||||||
|
.where(eq(fitnessGoals.id, id))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
return this.getFitnessGoalById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDashboardStats(): Promise<{
|
||||||
|
totalUsers: number;
|
||||||
|
activeClients: number;
|
||||||
|
totalRevenue: number;
|
||||||
|
revenueGrowth: number;
|
||||||
|
}> {
|
||||||
|
// Placeholder implementation as per original sqlite.ts (which didn't implement this either in the viewed snippet,
|
||||||
|
// but interface requires it. I'll provide a basic implementation or mock).
|
||||||
|
// The original sqlite.ts snippet ended before showing this method, but the interface has it.
|
||||||
|
// I'll implement a basic count.
|
||||||
|
|
||||||
|
const allUsers = await this.db.select().from(users).all();
|
||||||
|
const activeClients = await this.db
|
||||||
|
.select()
|
||||||
|
.from(clients)
|
||||||
|
.where(eq(clients.membershipStatus, "active"))
|
||||||
|
.all();
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalUsers: allUsers.length,
|
||||||
|
activeClients: activeClients.length,
|
||||||
|
totalRevenue: 0, // Not tracking payments yet
|
||||||
|
revenueGrowth: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mappers
|
||||||
|
private mapUser(row: any): User {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
gymId: (row as any).gymId ?? (row as any).gym_id ?? undefined,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
updatedAt: new Date(row.updatedAt),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapClient(row: any): Client {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
joinDate: new Date(row.joinDate),
|
||||||
|
lastVisit: row.lastVisit ? new Date(row.lastVisit) : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapFitnessProfile(row: any): FitnessProfile {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
updatedAt: new Date(row.updatedAt),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapAttendance(row: any): Attendance {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
checkInTime: new Date(row.checkInTime),
|
||||||
|
checkOutTime: row.checkOutTime ? new Date(row.checkOutTime) : undefined,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapRecommendation(row: any): Recommendation {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
approvedAt: row.approvedAt ? new Date(row.approvedAt) : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapFitnessGoal(row: any): FitnessGoal {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
startDate: new Date(row.startDate),
|
||||||
|
targetDate: row.targetDate ? new Date(row.targetDate) : undefined,
|
||||||
|
completedDate: row.completedDate
|
||||||
|
? new Date(row.completedDate)
|
||||||
|
: undefined,
|
||||||
|
createdAt: new Date(row.createdAt),
|
||||||
|
updatedAt: new Date(row.updatedAt),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IDatabase, DatabaseConfig } from './types'
|
import { IDatabase, DatabaseConfig } from './types'
|
||||||
import { SQLiteDatabase } from './sqlite'
|
import { DrizzleDatabase } from './drizzle'
|
||||||
|
|
||||||
// Database factory - creates appropriate database instance based on config
|
// Database factory - creates appropriate database instance based on config
|
||||||
export class DatabaseFactory {
|
export class DatabaseFactory {
|
||||||
@@ -20,7 +20,7 @@ export class DatabaseFactory {
|
|||||||
// Create new database instance based on type
|
// Create new database instance based on type
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case 'sqlite':
|
case 'sqlite':
|
||||||
this.instance = new SQLiteDatabase(config)
|
this.instance = new DrizzleDatabase(config)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'postgresql':
|
case 'postgresql':
|
||||||
|
|||||||
@@ -1,655 +0,0 @@
|
|||||||
import Database from 'better-sqlite3'
|
|
||||||
import path from 'path'
|
|
||||||
import fs from 'fs'
|
|
||||||
import { IDatabase, User, Client, FitnessProfile, Attendance, Recommendation, DatabaseConfig } from './types'
|
|
||||||
|
|
||||||
export class SQLiteDatabase implements IDatabase {
|
|
||||||
private db: Database.Database | null = null
|
|
||||||
private config: DatabaseConfig
|
|
||||||
|
|
||||||
constructor(config: DatabaseConfig) {
|
|
||||||
this.config = config
|
|
||||||
}
|
|
||||||
|
|
||||||
async connect(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const dbPath = this.config.connection.filename || path.join(process.cwd(), 'data', 'fitai.db')
|
|
||||||
|
|
||||||
// Ensure data directory exists
|
|
||||||
const dataDir = path.dirname(dbPath)
|
|
||||||
if (!fs.existsSync(dataDir)) {
|
|
||||||
fs.mkdirSync(dataDir, { recursive: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
this.db = new Database(dbPath)
|
|
||||||
|
|
||||||
// Enable foreign keys
|
|
||||||
this.db.exec('PRAGMA foreign_keys = ON')
|
|
||||||
|
|
||||||
// Create tables
|
|
||||||
await this.createTables()
|
|
||||||
|
|
||||||
if (this.config.options?.logging) {
|
|
||||||
console.log('SQLite database connected successfully at:', dbPath)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to connect to SQLite database:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async disconnect(): Promise<void> {
|
|
||||||
if (this.db) {
|
|
||||||
this.db.close()
|
|
||||||
this.db = null
|
|
||||||
if (this.config.options?.logging) {
|
|
||||||
console.log('SQLite database disconnected')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createTables(): Promise<void> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
// Users table
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
email TEXT UNIQUE NOT NULL,
|
|
||||||
firstName TEXT NOT NULL,
|
|
||||||
lastName TEXT NOT NULL,
|
|
||||||
password TEXT NOT NULL,
|
|
||||||
phone TEXT,
|
|
||||||
role TEXT NOT NULL CHECK (role IN ('superAdmin', 'admin', 'trainer', 'client')),
|
|
||||||
createdAt DATETIME NOT NULL,
|
|
||||||
updatedAt DATETIME NOT NULL
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Clients table
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS clients (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
userId TEXT NOT NULL,
|
|
||||||
membershipType TEXT NOT NULL CHECK (membershipType IN ('basic', 'premium', 'vip')),
|
|
||||||
membershipStatus TEXT NOT NULL CHECK (membershipStatus IN ('active', 'inactive', 'expired')),
|
|
||||||
joinDate DATETIME NOT NULL,
|
|
||||||
FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Fitness profiles table
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS fitness_profiles (
|
|
||||||
userId TEXT PRIMARY KEY,
|
|
||||||
height TEXT NOT NULL,
|
|
||||||
weight TEXT NOT NULL,
|
|
||||||
age TEXT NOT NULL,
|
|
||||||
gender TEXT NOT NULL CHECK (gender IN ('male', 'female', 'other')),
|
|
||||||
activityLevel TEXT NOT NULL CHECK (activityLevel IN ('sedentary', 'light', 'moderate', 'active', 'very_active')),
|
|
||||||
fitnessGoals TEXT NOT NULL, -- JSON array
|
|
||||||
exerciseHabits TEXT,
|
|
||||||
dietHabits TEXT,
|
|
||||||
medicalConditions TEXT,
|
|
||||||
allergies TEXT,
|
|
||||||
injuries TEXT,
|
|
||||||
createdAt DATETIME NOT NULL,
|
|
||||||
updatedAt DATETIME NOT NULL,
|
|
||||||
FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Create indexes for better performance
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_clients_userId ON clients(userId);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_fitness_profiles_userId ON fitness_profiles(userId);
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Attendance table
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS attendance (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
clientId TEXT NOT NULL,
|
|
||||||
checkInTime DATETIME NOT NULL,
|
|
||||||
checkOutTime DATETIME,
|
|
||||||
type TEXT NOT NULL CHECK (type IN ('gym', 'class', 'personal_training')),
|
|
||||||
notes TEXT,
|
|
||||||
createdAt DATETIME NOT NULL,
|
|
||||||
FOREIGN KEY (clientId) REFERENCES clients (id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Recommendations table
|
|
||||||
// Removed DROP TABLE to persist data. Schema is now stable.
|
|
||||||
// this.db.exec(`DROP TABLE IF EXISTS recommendations`)
|
|
||||||
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS recommendations (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
userId TEXT NOT NULL,
|
|
||||||
fitnessProfileId TEXT,
|
|
||||||
type TEXT NOT NULL,
|
|
||||||
content TEXT NOT NULL,
|
|
||||||
activityPlan TEXT,
|
|
||||||
dietPlan TEXT,
|
|
||||||
status TEXT NOT NULL CHECK (status IN ('pending', 'approved', 'rejected', 'completed')),
|
|
||||||
createdAt DATETIME NOT NULL,
|
|
||||||
approvedAt DATETIME,
|
|
||||||
approvedBy TEXT,
|
|
||||||
FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (fitnessProfileId) REFERENCES fitness_profiles (userId)
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_recommendations_userId ON recommendations(userId);
|
|
||||||
`)
|
|
||||||
|
|
||||||
this.db.exec(`
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_attendance_clientId ON attendance(clientId);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_attendance_checkInTime ON attendance(checkInTime);
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// User operations
|
|
||||||
async createUser(
|
|
||||||
userData: Omit<User, "createdAt" | "updatedAt" | "id"> & { id?: string },
|
|
||||||
): Promise<User> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const id = userData.id || Math.random().toString(36).substr(2, 9)
|
|
||||||
const now = new Date()
|
|
||||||
|
|
||||||
const user: User = {
|
|
||||||
...userData,
|
|
||||||
id,
|
|
||||||
createdAt: now,
|
|
||||||
updatedAt: now
|
|
||||||
}
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(
|
|
||||||
`INSERT INTO users(id, email, firstName, lastName, password, phone, role, createdAt, updatedAt)
|
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
||||||
)
|
|
||||||
|
|
||||||
stmt.run(
|
|
||||||
user.id, user.email, user.firstName, user.lastName, user.password,
|
|
||||||
user.phone, user.role, user.createdAt.toISOString(), user.updatedAt.toISOString()
|
|
||||||
)
|
|
||||||
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUserById(id: string): Promise<User | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM users WHERE id = ?')
|
|
||||||
const row = stmt.get(id)
|
|
||||||
|
|
||||||
return row ? this.mapRowToUser(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUserByEmail(email: string): Promise<User | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM users WHERE email = ?')
|
|
||||||
const row = stmt.get(email)
|
|
||||||
|
|
||||||
return row ? this.mapRowToUser(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllUsers(): Promise<User[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM users ORDER BY createdAt DESC')
|
|
||||||
const rows = stmt.all()
|
|
||||||
|
|
||||||
return rows.map(row => this.mapRowToUser(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateUser(id: string, updates: Partial<User>): Promise<User | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const fields = Object.keys(updates).filter(key => key !== 'id')
|
|
||||||
if (fields.length === 0) return this.getUserById(id)
|
|
||||||
|
|
||||||
const setClause = fields.map(field => `${field} = ?`).join(', ')
|
|
||||||
const values = fields.map(field => (updates as any)[field])
|
|
||||||
values.push(new Date().toISOString()) // updatedAt
|
|
||||||
values.push(id)
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(`UPDATE users SET ${setClause}, updatedAt = ? WHERE id = ? `)
|
|
||||||
stmt.run(values)
|
|
||||||
|
|
||||||
return this.getUserById(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteUser(id: string): Promise<boolean> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('DELETE FROM users WHERE id = ?')
|
|
||||||
const result = stmt.run(id)
|
|
||||||
return (result.changes || 0) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
async migrateUserId(oldId: string, newId: string): Promise<void> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
// We need to disable foreign keys temporarily if we want to update ID without cascade (if cascade isn't set)
|
|
||||||
// But we should try to update and let cascade handle it if possible.
|
|
||||||
// Since we didn't set ON UPDATE CASCADE, we might need to manually update references or use PRAGMA.
|
|
||||||
|
|
||||||
// Simplest way: Update the ID. If it fails due to FK, we have to handle it.
|
|
||||||
// For the Super Admin seed case, there are no dependencies.
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('UPDATE users SET id = ? WHERE id = ?')
|
|
||||||
stmt.run(newId, oldId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client operations
|
|
||||||
async createClient(clientData: Omit<Client, 'id'>): Promise<Client> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const id = Math.random().toString(36).substr(2, 9)
|
|
||||||
const client: Client = { id, ...clientData }
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(
|
|
||||||
`INSERT INTO clients(id, userId, membershipType, membershipStatus, joinDate)
|
|
||||||
VALUES(?, ?, ?, ?, ?)`
|
|
||||||
)
|
|
||||||
|
|
||||||
stmt.run(
|
|
||||||
client.id, client.userId, client.membershipType,
|
|
||||||
client.membershipStatus, client.joinDate.toISOString()
|
|
||||||
)
|
|
||||||
|
|
||||||
return client
|
|
||||||
}
|
|
||||||
|
|
||||||
async getClientById(id: string): Promise<Client | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM clients WHERE id = ?')
|
|
||||||
const row = stmt.get(id)
|
|
||||||
return row ? this.mapRowToClient(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async getClientByUserId(userId: string): Promise<Client | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM clients WHERE userId = ?')
|
|
||||||
const row = stmt.get(userId)
|
|
||||||
return row ? this.mapRowToClient(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllClients(): Promise<Client[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM clients ORDER BY joinDate DESC')
|
|
||||||
const rows = stmt.all()
|
|
||||||
return rows.map(row => this.mapRowToClient(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateClient(id: string, updates: Partial<Client>): Promise<Client | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const fields = Object.keys(updates).filter(key => key !== 'id')
|
|
||||||
if (fields.length === 0) return this.getClientById(id)
|
|
||||||
|
|
||||||
const setClause = fields.map(field => `${field} = ?`).join(', ')
|
|
||||||
const values = fields.map(field => (updates as any)[field])
|
|
||||||
values.push(id)
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(`UPDATE clients SET ${setClause} WHERE id = ? `)
|
|
||||||
stmt.run(values)
|
|
||||||
|
|
||||||
return this.getClientById(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteClient(id: string): Promise<boolean> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('DELETE FROM clients WHERE id = ?')
|
|
||||||
const result = stmt.run(id)
|
|
||||||
return (result.changes || 0) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fitness Profile operations
|
|
||||||
async createFitnessProfile(profileData: Omit<FitnessProfile, 'createdAt' | 'updatedAt'>): Promise<FitnessProfile> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const now = new Date()
|
|
||||||
const profile: FitnessProfile = {
|
|
||||||
...profileData,
|
|
||||||
createdAt: now,
|
|
||||||
updatedAt: now
|
|
||||||
}
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(
|
|
||||||
`INSERT INTO fitness_profiles
|
|
||||||
(userId, height, weight, age, gender, activityLevel, fitnessGoals,
|
|
||||||
exerciseHabits, dietHabits, medicalConditions, allergies, injuries, createdAt, updatedAt)
|
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
||||||
)
|
|
||||||
|
|
||||||
stmt.run(
|
|
||||||
profile.userId, profile.height, profile.weight, profile.age, profile.gender,
|
|
||||||
profile.activityLevel, JSON.stringify(profile.fitnessGoals), profile.exerciseHabits,
|
|
||||||
profile.dietHabits, profile.medicalConditions, profile.allergies, profile.injuries,
|
|
||||||
profile.createdAt.toISOString(), profile.updatedAt.toISOString()
|
|
||||||
)
|
|
||||||
|
|
||||||
return profile
|
|
||||||
}
|
|
||||||
|
|
||||||
async getFitnessProfileByUserId(userId: string): Promise<FitnessProfile | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM fitness_profiles WHERE userId = ?')
|
|
||||||
const row = stmt.get(userId)
|
|
||||||
|
|
||||||
return row ? this.mapRowToFitnessProfile(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllFitnessProfiles(): Promise<FitnessProfile[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM fitness_profiles ORDER BY createdAt DESC')
|
|
||||||
const rows = stmt.all()
|
|
||||||
return rows.map(row => this.mapRowToFitnessProfile(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateFitnessProfile(userId: string, updates: Partial<FitnessProfile>): Promise<FitnessProfile | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const fields = Object.keys(updates).filter(key => key !== 'userId' && key !== 'createdAt')
|
|
||||||
if (fields.length === 0) return this.getFitnessProfileByUserId(userId)
|
|
||||||
|
|
||||||
const setClause = fields.map(field => `${field} = ?`).join(', ')
|
|
||||||
const values = fields.map(field => {
|
|
||||||
const value = (updates as any)[field]
|
|
||||||
return field === 'fitnessGoals' ? JSON.stringify(value) : value
|
|
||||||
})
|
|
||||||
values.push(new Date().toISOString()) // updatedAt
|
|
||||||
values.push(userId)
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(`UPDATE fitness_profiles SET ${setClause}, updatedAt = ? WHERE userId = ? `)
|
|
||||||
stmt.run(values)
|
|
||||||
|
|
||||||
return this.getFitnessProfileByUserId(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteFitnessProfile(userId: string): Promise<boolean> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('DELETE FROM fitness_profiles WHERE userId = ?')
|
|
||||||
const result = stmt.run(userId)
|
|
||||||
return (result.changes || 0) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attendance operations
|
|
||||||
async checkIn(clientId: string, type: 'gym' | 'class' | 'personal_training', notes?: string): Promise<Attendance> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const id = Math.random().toString(36).substr(2, 9)
|
|
||||||
const now = new Date()
|
|
||||||
|
|
||||||
const attendance: Attendance = {
|
|
||||||
id,
|
|
||||||
clientId,
|
|
||||||
checkInTime: now,
|
|
||||||
type,
|
|
||||||
notes,
|
|
||||||
createdAt: now
|
|
||||||
}
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(
|
|
||||||
`INSERT INTO attendance(id, clientId, checkInTime, type, notes, createdAt)
|
|
||||||
VALUES(?, ?, ?, ?, ?, ?)`
|
|
||||||
)
|
|
||||||
|
|
||||||
stmt.run(
|
|
||||||
attendance.id, attendance.clientId, attendance.checkInTime.toISOString(),
|
|
||||||
attendance.type, attendance.notes, attendance.createdAt.toISOString()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update client last visit
|
|
||||||
this.db.prepare('UPDATE clients SET lastVisit = ? WHERE id = ?').run(
|
|
||||||
now.toISOString(),
|
|
||||||
clientId
|
|
||||||
)
|
|
||||||
|
|
||||||
return attendance
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkOut(attendanceId: string): Promise<Attendance | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const now = new Date()
|
|
||||||
const stmt = this.db.prepare('UPDATE attendance SET checkOutTime = ? WHERE id = ?')
|
|
||||||
stmt.run(now.toISOString(), attendanceId)
|
|
||||||
|
|
||||||
return this.getAttendanceById(attendanceId)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAttendanceById(id: string): Promise<Attendance | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM attendance WHERE id = ?')
|
|
||||||
const row = stmt.get(id)
|
|
||||||
return row ? this.mapRowToAttendance(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAttendanceHistory(clientId: string): Promise<Attendance[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM attendance WHERE clientId = ? ORDER BY checkInTime DESC')
|
|
||||||
const rows = stmt.all(clientId)
|
|
||||||
return rows.map(row => this.mapRowToAttendance(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllAttendance(): Promise<Attendance[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM attendance ORDER BY checkInTime DESC')
|
|
||||||
const rows = stmt.all()
|
|
||||||
return rows.map(row => this.mapRowToAttendance(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async getActiveCheckIn(clientId: string): Promise<Attendance | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM attendance WHERE clientId = ? AND checkOutTime IS NULL ORDER BY checkInTime DESC LIMIT 1')
|
|
||||||
const row = stmt.get(clientId)
|
|
||||||
return row ? this.mapRowToAttendance(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper methods to map database rows to entities
|
|
||||||
private mapRowToUser(row: any): User {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
email: row.email,
|
|
||||||
firstName: row.firstName,
|
|
||||||
lastName: row.lastName,
|
|
||||||
password: row.password,
|
|
||||||
phone: row.phone,
|
|
||||||
role: row.role,
|
|
||||||
createdAt: new Date(row.createdAt),
|
|
||||||
updatedAt: new Date(row.updatedAt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapRowToClient(row: any): Client {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
userId: row.userId,
|
|
||||||
membershipType: row.membershipType,
|
|
||||||
membershipStatus: row.membershipStatus,
|
|
||||||
joinDate: new Date(row.joinDate),
|
|
||||||
lastVisit: row.lastVisit ? new Date(row.lastVisit) : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapRowToFitnessProfile(row: any): FitnessProfile {
|
|
||||||
return {
|
|
||||||
userId: row.userId,
|
|
||||||
height: row.height,
|
|
||||||
weight: row.weight,
|
|
||||||
age: row.age,
|
|
||||||
gender: row.gender,
|
|
||||||
activityLevel: row.activityLevel,
|
|
||||||
fitnessGoals: JSON.parse(row.fitnessGoals || '[]'),
|
|
||||||
exerciseHabits: row.exerciseHabits,
|
|
||||||
dietHabits: row.dietHabits,
|
|
||||||
medicalConditions: row.medicalConditions,
|
|
||||||
allergies: row.allergies,
|
|
||||||
injuries: row.injuries,
|
|
||||||
createdAt: new Date(row.createdAt),
|
|
||||||
updatedAt: new Date(row.updatedAt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapRowToAttendance(row: any): Attendance {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
clientId: row.clientId,
|
|
||||||
checkInTime: new Date(row.checkInTime),
|
|
||||||
checkOutTime: row.checkOutTime ? new Date(row.checkOutTime) : undefined,
|
|
||||||
type: row.type,
|
|
||||||
notes: row.notes,
|
|
||||||
createdAt: new Date(row.createdAt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recommendation operations
|
|
||||||
async createRecommendation(data: Omit<Recommendation, 'createdAt' | 'approvedAt' | 'approvedBy'>): Promise<Recommendation> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const now = new Date()
|
|
||||||
const recommendation: Recommendation = {
|
|
||||||
...data,
|
|
||||||
createdAt: now,
|
|
||||||
status: data.status || 'pending'
|
|
||||||
}
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(
|
|
||||||
`INSERT INTO recommendations (
|
|
||||||
id, userId, fitnessProfileId, type, content,
|
|
||||||
activityPlan, dietPlan, status, createdAt
|
|
||||||
)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
||||||
)
|
|
||||||
|
|
||||||
stmt.run(
|
|
||||||
recommendation.id, recommendation.userId, recommendation.fitnessProfileId,
|
|
||||||
recommendation.type, recommendation.content, recommendation.activityPlan,
|
|
||||||
recommendation.dietPlan, recommendation.status,
|
|
||||||
recommendation.createdAt.toISOString()
|
|
||||||
)
|
|
||||||
|
|
||||||
return recommendation
|
|
||||||
}
|
|
||||||
|
|
||||||
async getRecommendationsByUserId(userId: string): Promise<Recommendation[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM recommendations WHERE userId = ? ORDER BY createdAt DESC')
|
|
||||||
const rows = stmt.all(userId)
|
|
||||||
|
|
||||||
return rows.map(row => this.mapRowToRecommendation(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllRecommendations(): Promise<Recommendation[]> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM recommendations ORDER BY createdAt DESC')
|
|
||||||
const rows = stmt.all()
|
|
||||||
|
|
||||||
return rows.map(row => this.mapRowToRecommendation(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateRecommendation(id: string, updates: Partial<Recommendation>): Promise<Recommendation | null> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const fields = Object.keys(updates).filter(key => key !== 'id' && key !== 'userId')
|
|
||||||
if (fields.length === 0) {
|
|
||||||
const stmt = this.db.prepare('SELECT * FROM recommendations WHERE id = ?')
|
|
||||||
const row = stmt.get(id)
|
|
||||||
return row ? this.mapRowToRecommendation(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
const setClause = fields.map(field => `${field} = ?`).join(', ')
|
|
||||||
const values = fields.map(field => {
|
|
||||||
const val = (updates as any)[field]
|
|
||||||
return val instanceof Date ? val.toISOString() : val
|
|
||||||
})
|
|
||||||
values.push(id)
|
|
||||||
|
|
||||||
const stmt = this.db.prepare(`UPDATE recommendations SET ${setClause} WHERE id = ?`)
|
|
||||||
stmt.run(values)
|
|
||||||
|
|
||||||
const getStmt = this.db.prepare('SELECT * FROM recommendations WHERE id = ?')
|
|
||||||
const row = getStmt.get(id)
|
|
||||||
return row ? this.mapRowToRecommendation(row) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteRecommendation(id: string): Promise<boolean> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
const stmt = this.db.prepare('DELETE FROM recommendations WHERE id = ?')
|
|
||||||
const result = stmt.run(id)
|
|
||||||
return (result.changes || 0) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapRowToRecommendation(row: any): Recommendation {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
userId: row.userId,
|
|
||||||
fitnessProfileId: row.fitnessProfileId,
|
|
||||||
type: row.type,
|
|
||||||
content: row.content,
|
|
||||||
activityPlan: row.activityPlan,
|
|
||||||
dietPlan: row.dietPlan,
|
|
||||||
status: row.status,
|
|
||||||
createdAt: new Date(row.createdAt),
|
|
||||||
approvedAt: row.approvedAt ? new Date(row.approvedAt) : undefined,
|
|
||||||
approvedBy: row.approvedBy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDashboardStats(): Promise<{
|
|
||||||
totalUsers: number;
|
|
||||||
activeClients: number;
|
|
||||||
totalRevenue: number;
|
|
||||||
revenueGrowth: number;
|
|
||||||
}> {
|
|
||||||
if (!this.db) throw new Error('Database not connected')
|
|
||||||
|
|
||||||
// Total Users
|
|
||||||
const userCountStmt = this.db.prepare('SELECT COUNT(*) as count FROM users')
|
|
||||||
const userCount = (userCountStmt.get() as any).count
|
|
||||||
|
|
||||||
// Active Clients
|
|
||||||
const activeClientCountStmt = this.db.prepare("SELECT COUNT(*) as count FROM clients WHERE membershipStatus = 'active'")
|
|
||||||
const activeClientCount = (activeClientCountStmt.get() as any).count
|
|
||||||
|
|
||||||
// Total Revenue (assuming payments table exists, handling if it's empty)
|
|
||||||
// Note: We need to create the payments table first if it doesn't exist in createTables
|
|
||||||
// For now, returning 0 if table doesn't exist or is empty
|
|
||||||
let totalRevenue = 0
|
|
||||||
let revenueGrowth = 0
|
|
||||||
|
|
||||||
try {
|
|
||||||
const revenueStmt = this.db.prepare('SELECT SUM(amount) as total FROM payments WHERE status = "completed"')
|
|
||||||
const revenueResult = revenueStmt.get() as any
|
|
||||||
totalRevenue = revenueResult?.total || 0
|
|
||||||
} catch (e) {
|
|
||||||
// Table might not exist yet
|
|
||||||
console.warn('Payments table query failed, returning 0 revenue')
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
totalUsers: userCount,
|
|
||||||
activeClients: activeClientCount,
|
|
||||||
totalRevenue,
|
|
||||||
revenueGrowth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +1,20 @@
|
|||||||
|
import {
|
||||||
|
User as SharedUser,
|
||||||
|
Client,
|
||||||
|
FitnessProfile,
|
||||||
|
Attendance,
|
||||||
|
Recommendation,
|
||||||
|
FitnessGoal,
|
||||||
|
} from "@fitai/shared";
|
||||||
|
|
||||||
// Database Entity Types
|
// Database Entity Types
|
||||||
export interface User {
|
export interface User extends SharedUser {
|
||||||
id: string;
|
// Explicitly include gymId so server imports can rely on it even if shared types lag behind build
|
||||||
email: string;
|
gymId?: string;
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
password: string;
|
password: string;
|
||||||
phone?: string;
|
|
||||||
role: "superAdmin" | "admin" | "trainer" | "client";
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Client {
|
export type { Client, FitnessProfile, Attendance, Recommendation, FitnessGoal };
|
||||||
id: string;
|
|
||||||
userId: string;
|
|
||||||
membershipType: "basic" | "premium" | "vip";
|
|
||||||
membershipStatus: "active" | "inactive" | "expired";
|
|
||||||
joinDate: Date;
|
|
||||||
lastVisit?: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FitnessProfile {
|
|
||||||
userId: string;
|
|
||||||
height: string;
|
|
||||||
weight: string;
|
|
||||||
age: string;
|
|
||||||
gender: "male" | "female" | "other";
|
|
||||||
activityLevel: "sedentary" | "light" | "moderate" | "active" | "very_active";
|
|
||||||
fitnessGoals: string[];
|
|
||||||
exerciseHabits: string;
|
|
||||||
dietHabits: string;
|
|
||||||
medicalConditions: string;
|
|
||||||
allergies?: string;
|
|
||||||
injuries?: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Attendance {
|
|
||||||
id: string;
|
|
||||||
clientId: string;
|
|
||||||
checkInTime: Date;
|
|
||||||
checkOutTime?: Date;
|
|
||||||
type: "gym" | "class" | "personal_training";
|
|
||||||
notes?: string;
|
|
||||||
createdAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Recommendation {
|
|
||||||
id: string;
|
|
||||||
userId: string;
|
|
||||||
fitnessProfileId?: string;
|
|
||||||
type: "short_term" | "medium_term" | "long_term" | "ai_plan";
|
|
||||||
content: string;
|
|
||||||
activityPlan?: string;
|
|
||||||
dietPlan?: string;
|
|
||||||
status: "pending" | "approved" | "rejected" | "completed";
|
|
||||||
createdAt: Date;
|
|
||||||
approvedAt?: Date;
|
|
||||||
approvedBy?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Database Interface - allows us to swap implementations
|
// Database Interface - allows us to swap implementations
|
||||||
export interface IDatabase {
|
export interface IDatabase {
|
||||||
@@ -100,18 +55,21 @@ export interface IDatabase {
|
|||||||
|
|
||||||
// Attendance operations
|
// Attendance operations
|
||||||
checkIn(
|
checkIn(
|
||||||
clientId: string,
|
userId: string,
|
||||||
type: "gym" | "class" | "personal_training",
|
type: "gym" | "class" | "personal_training",
|
||||||
notes?: string,
|
notes?: string,
|
||||||
): Promise<Attendance>;
|
): Promise<Attendance>;
|
||||||
checkOut(attendanceId: string): Promise<Attendance | null>;
|
checkOut(attendanceId: string): Promise<Attendance | null>;
|
||||||
getAttendanceHistory(clientId: string): Promise<Attendance[]>;
|
getAttendanceHistory(userId: string): Promise<Attendance[]>;
|
||||||
getAllAttendance(): Promise<Attendance[]>;
|
getAllAttendance(): Promise<Attendance[]>;
|
||||||
getActiveCheckIn(clientId: string): Promise<Attendance | null>;
|
getActiveCheckIn(userId: string): Promise<Attendance | null>;
|
||||||
|
|
||||||
// Recommendation operations
|
// Recommendation operations
|
||||||
createRecommendation(
|
createRecommendation(
|
||||||
recommendation: Omit<Recommendation, "createdAt" | "approvedAt" | "approvedBy">,
|
recommendation: Omit<
|
||||||
|
Recommendation,
|
||||||
|
"createdAt" | "approvedAt" | "approvedBy"
|
||||||
|
>,
|
||||||
): Promise<Recommendation>;
|
): Promise<Recommendation>;
|
||||||
getRecommendationsByUserId(userId: string): Promise<Recommendation[]>;
|
getRecommendationsByUserId(userId: string): Promise<Recommendation[]>;
|
||||||
getAllRecommendations(): Promise<Recommendation[]>;
|
getAllRecommendations(): Promise<Recommendation[]>;
|
||||||
@@ -121,6 +79,26 @@ export interface IDatabase {
|
|||||||
): Promise<Recommendation | null>;
|
): Promise<Recommendation | null>;
|
||||||
deleteRecommendation(id: string): Promise<boolean>;
|
deleteRecommendation(id: string): Promise<boolean>;
|
||||||
|
|
||||||
|
// Fitness Goals operations
|
||||||
|
createFitnessGoal(
|
||||||
|
goal: Omit<FitnessGoal, "createdAt" | "updatedAt">,
|
||||||
|
): Promise<FitnessGoal>;
|
||||||
|
getFitnessGoalById(id: string): Promise<FitnessGoal | null>;
|
||||||
|
getFitnessGoalsByUserId(
|
||||||
|
userId: string,
|
||||||
|
status?: string,
|
||||||
|
): Promise<FitnessGoal[]>;
|
||||||
|
updateFitnessGoal(
|
||||||
|
id: string,
|
||||||
|
updates: Partial<FitnessGoal>,
|
||||||
|
): Promise<FitnessGoal | null>;
|
||||||
|
deleteFitnessGoal(id: string): Promise<boolean>;
|
||||||
|
updateGoalProgress(
|
||||||
|
id: string,
|
||||||
|
currentValue: number,
|
||||||
|
): Promise<FitnessGoal | null>;
|
||||||
|
completeGoal(id: string): Promise<FitnessGoal | null>;
|
||||||
|
|
||||||
// Dashboard operations
|
// Dashboard operations
|
||||||
getDashboardStats(): Promise<{
|
getDashboardStats(): Promise<{
|
||||||
totalUsers: number;
|
totalUsers: number;
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
import { currentUser } from '@clerk/nextjs/server'
|
import { currentUser } from "@clerk/nextjs/server";
|
||||||
import { IDatabase } from './database/types'
|
import type { IDatabase, User } from "./database/types";
|
||||||
|
|
||||||
export async function ensureUserSynced(userId: string, db: IDatabase) {
|
export async function ensureUserSynced(
|
||||||
const existingUser = await db.getUserById(userId)
|
userId: string,
|
||||||
if (existingUser) return existingUser
|
db: IDatabase,
|
||||||
|
): Promise<User | null> {
|
||||||
|
const existingUser = await db.getUserById(userId);
|
||||||
|
if (existingUser) return existingUser;
|
||||||
|
|
||||||
console.log('User not found in DB by ID, checking Clerk:', userId)
|
console.log("User not found in DB by ID, checking Clerk:", userId);
|
||||||
const clerkUser = await currentUser()
|
const clerkUser = await currentUser();
|
||||||
|
|
||||||
if (!clerkUser || clerkUser.id !== userId) {
|
if (!clerkUser || clerkUser.id !== userId) {
|
||||||
// If we can't get the user from Clerk (e.g. running locally without full auth sync),
|
// If we can't get the user from Clerk (e.g. running locally without full auth sync),
|
||||||
// we might want to fail gracefully or throw.
|
// we might want to fail gracefully or throw.
|
||||||
// For now, throw to be safe.
|
// For now, throw to be safe.
|
||||||
throw new Error('Could not fetch Clerk user details')
|
throw new Error("Could not fetch Clerk user details");
|
||||||
}
|
}
|
||||||
|
|
||||||
const email = clerkUser.emailAddresses[0]?.emailAddress
|
const email = clerkUser.emailAddresses[0]?.emailAddress;
|
||||||
if (!email) throw new Error('User has no email')
|
if (!email) throw new Error("User has no email");
|
||||||
|
|
||||||
// Check if user exists by email (e.g. seeded user)
|
// Check if user exists by email (e.g. seeded user)
|
||||||
const existingByEmail = await db.getUserByEmail(email)
|
const existingByEmail = await db.getUserByEmail(email);
|
||||||
if (existingByEmail) {
|
if (existingByEmail) {
|
||||||
console.log('User found by email but ID mismatch. Migrating ID...', {
|
console.log("User found by email but ID mismatch. Migrating ID...", {
|
||||||
oldId: existingByEmail.id,
|
oldId: existingByEmail.id,
|
||||||
newId: userId
|
newId: userId,
|
||||||
})
|
});
|
||||||
|
|
||||||
// Update the ID to match Clerk ID
|
// Update the ID to match Clerk ID
|
||||||
// We need to do this manually via SQL because IDatabase interface might not expose a direct ID update method easily
|
// We need to do this manually via SQL because IDatabase interface might not expose a direct ID update method easily
|
||||||
@@ -43,20 +46,27 @@ export async function ensureUserSynced(userId: string, db: IDatabase) {
|
|||||||
// However, if they had clients, we'd lose the link.
|
// However, if they had clients, we'd lose the link.
|
||||||
|
|
||||||
// Let's add `migrateUserId(oldId, newId)` to IDatabase.
|
// Let's add `migrateUserId(oldId, newId)` to IDatabase.
|
||||||
await db.migrateUserId(existingByEmail.id, userId)
|
await db.migrateUserId(existingByEmail.id, userId);
|
||||||
return db.getUserById(userId)
|
return db.getUserById(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Creating new user from Clerk data:', userId)
|
console.log("Creating new user from Clerk data:", userId);
|
||||||
const user = await db.createUser({
|
const user = await db.createUser({
|
||||||
id: userId,
|
id: userId,
|
||||||
email,
|
email,
|
||||||
firstName: clerkUser.firstName || '',
|
firstName: clerkUser.firstName || "",
|
||||||
lastName: clerkUser.lastName || '',
|
lastName: clerkUser.lastName || "",
|
||||||
password: '', // Managed by Clerk
|
password: "", // Managed by Clerk
|
||||||
phone: clerkUser.phoneNumbers[0]?.phoneNumber || undefined,
|
phone: clerkUser.phoneNumbers[0]?.phoneNumber || undefined,
|
||||||
role: (clerkUser.publicMetadata.role as 'admin' | 'client' | 'superAdmin') || 'client'
|
gymId: (clerkUser.publicMetadata.gymId as string | undefined) || undefined,
|
||||||
})
|
role: ((): any => {
|
||||||
|
const r = clerkUser.publicMetadata.role as string | undefined;
|
||||||
|
return r &&
|
||||||
|
["superAdmin", "admin", "trainer", "client", "generalUser"].includes(r)
|
||||||
|
? r
|
||||||
|
: "client";
|
||||||
|
})(),
|
||||||
|
});
|
||||||
|
|
||||||
return user
|
return user;
|
||||||
}
|
}
|
||||||
@@ -1,14 +1 @@
|
|||||||
import { type ClassValue, clsx } from "clsx"
|
export { cn, formatDate } from "@fitai/shared"
|
||||||
import { twMerge } from "tailwind-merge"
|
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
|
||||||
return twMerge(clsx(inputs))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatDate(date: string | Date) {
|
|
||||||
return new Date(date).toLocaleDateString("en-US", {
|
|
||||||
month: "long",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Values used to calculate the hash in this folder name.
|
||||||
|
# Should not depend on the absolute path of the project itself.
|
||||||
|
# - AGP: 8.11.0.
|
||||||
|
# - $NDK is the path to NDK 27.1.12297006.
|
||||||
|
# - $PROJECT is the path to the parent folder of the root Gradle build file.
|
||||||
|
# - $ABI is the ABI to be built with. The specific value doesn't contribute to the value of the hash.
|
||||||
|
# - $HASH is the hash value computed from this text.
|
||||||
|
# - $CMAKE is the path to CMake 3.22.1.
|
||||||
|
# - $NINJA is the path to Ninja.
|
||||||
|
-H/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup
|
||||||
|
-DCMAKE_SYSTEM_NAME=Android
|
||||||
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
-DCMAKE_SYSTEM_VERSION=26
|
||||||
|
-DANDROID_PLATFORM=android-26
|
||||||
|
-DANDROID_ABI=$ABI
|
||||||
|
-DCMAKE_ANDROID_ARCH_ABI=$ABI
|
||||||
|
-DANDROID_NDK=$NDK
|
||||||
|
-DCMAKE_ANDROID_NDK=$NDK
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake
|
||||||
|
-DCMAKE_MAKE_PROGRAM=$NINJA
|
||||||
|
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=$PROJECT/app/build/intermediates/cxx/Debug/$HASH/obj/$ABI
|
||||||
|
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=$PROJECT/app/build/intermediates/cxx/Debug/$HASH/obj/$ABI
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug
|
||||||
|
-DCMAKE_FIND_ROOT_PATH=$PROJECT/app/.cxx/Debug/$HASH/prefab/$ABI/prefab
|
||||||
|
-B$PROJECT/app/.cxx/Debug/$HASH/$ABI
|
||||||
|
-GNinja
|
||||||
|
-DPROJECT_BUILD_DIR=$PROJECT/app/build
|
||||||
|
-DPROJECT_ROOT_DIR=$PROJECT
|
||||||
|
-DREACT_ANDROID_DIR=/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid
|
||||||
|
-DANDROID_STL=c++_shared
|
||||||
|
-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
if(NOT TARGET ReactAndroid::hermestooling)
|
||||||
|
add_library(ReactAndroid::hermestooling SHARED IMPORTED)
|
||||||
|
set_target_properties(ReactAndroid::hermestooling PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/hermestooling/libs/android.x86/libhermestooling.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/hermestooling/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET ReactAndroid::jsi)
|
||||||
|
add_library(ReactAndroid::jsi SHARED IMPORTED)
|
||||||
|
set_target_properties(ReactAndroid::jsi PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/jsi/libs/android.x86/libjsi.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/jsi/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET ReactAndroid::reactnative)
|
||||||
|
add_library(ReactAndroid::reactnative SHARED IMPORTED)
|
||||||
|
set_target_properties(ReactAndroid::reactnative PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/reactnative/libs/android.x86/libreactnative.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/reactnative/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
set(PACKAGE_VERSION 0.81.5)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
if(NOT TARGET fbjni::fbjni)
|
||||||
|
add_library(fbjni::fbjni SHARED IMPORTED)
|
||||||
|
set_target_properties(fbjni::fbjni PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/488fe6e480efb97ec75859f6e274282f/transformed/fbjni-0.7.0/prefab/modules/fbjni/libs/android.x86/libfbjni.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/488fe6e480efb97ec75859f6e274282f/transformed/fbjni-0.7.0/prefab/modules/fbjni/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
set(PACKAGE_VERSION 3.22.1)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
if(NOT TARGET hermes-engine::libhermes)
|
||||||
|
add_library(hermes-engine::libhermes SHARED IMPORTED)
|
||||||
|
set_target_properties(hermes-engine::libhermes PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/f3d279cf13499f4c93e2b512ac9499e6/transformed/hermes-android-0.81.5-debug/prefab/modules/libhermes/libs/android.x86/libhermes.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/f3d279cf13499f4c93e2b512ac9499e6/transformed/hermes-android-0.81.5-debug/prefab/modules/libhermes/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
set(PACKAGE_VERSION 0.81.5)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
if(NOT TARGET ReactAndroid::hermestooling)
|
||||||
|
add_library(ReactAndroid::hermestooling SHARED IMPORTED)
|
||||||
|
set_target_properties(ReactAndroid::hermestooling PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/hermestooling/libs/android.x86_64/libhermestooling.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/hermestooling/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET ReactAndroid::jsi)
|
||||||
|
add_library(ReactAndroid::jsi SHARED IMPORTED)
|
||||||
|
set_target_properties(ReactAndroid::jsi PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/jsi/libs/android.x86_64/libjsi.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/jsi/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET ReactAndroid::reactnative)
|
||||||
|
add_library(ReactAndroid::reactnative SHARED IMPORTED)
|
||||||
|
set_target_properties(ReactAndroid::reactnative PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/reactnative/libs/android.x86_64/libreactnative.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/reactnative/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
set(PACKAGE_VERSION 0.81.5)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
if(NOT TARGET fbjni::fbjni)
|
||||||
|
add_library(fbjni::fbjni SHARED IMPORTED)
|
||||||
|
set_target_properties(fbjni::fbjni PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/488fe6e480efb97ec75859f6e274282f/transformed/fbjni-0.7.0/prefab/modules/fbjni/libs/android.x86_64/libfbjni.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/488fe6e480efb97ec75859f6e274282f/transformed/fbjni-0.7.0/prefab/modules/fbjni/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
set(PACKAGE_VERSION 3.22.1)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
if(NOT TARGET hermes-engine::libhermes)
|
||||||
|
add_library(hermes-engine::libhermes SHARED IMPORTED)
|
||||||
|
set_target_properties(hermes-engine::libhermes PROPERTIES
|
||||||
|
IMPORTED_LOCATION "/home/echo/.gradle/caches/8.14.3/transforms/f3d279cf13499f4c93e2b512ac9499e6/transformed/hermes-android-0.81.5-debug/prefab/modules/libhermes/libs/android.x86_64/libhermes.so"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "/home/echo/.gradle/caches/8.14.3/transforms/f3d279cf13499f4c93e2b512ac9499e6/transformed/hermes-android-0.81.5-debug/prefab/modules/libhermes/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
set(PACKAGE_VERSION 0.81.5)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
+1439
File diff suppressed because it is too large.
Load diff
+851
@@ -0,0 +1,851 @@
|
|||||||
|
{
|
||||||
|
"inputs" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path" : "CMakeLists.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineSystem.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/android.toolchain.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/android-legacy.toolchain.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/abis.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/platforms.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Determine.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/hooks/pre/Android-Determine.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeSystem.cmake.in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isGenerated" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/3.22.1-g37088a8/CMakeSystem.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/android.toolchain.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeSystemSpecificInitialize.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Initialize.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/hooks/pre/Android-Initialize.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Determine-C.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android/Determine-Compiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/hooks/pre/Determine-Compiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerId.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCompilerIdDetection.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ADSP-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Borland-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Bruce-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Compaq-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Cray-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GHS-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GNU-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/HP-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IAR-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Intel-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/MSVC-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PGI-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PathScale-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SCO-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SDCC-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SunPro-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/TI-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Watcom-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XL-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XLClang-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/zOS-C-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeFindBinUtils.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-FindBinUtils.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCCompiler.cmake.in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isGenerated" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/3.22.1-g37088a8/CMakeCCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCXXCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Determine-CXX.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android/Determine-Compiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerId.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCompilerIdDetection.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ADSP-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Borland-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Cray-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GHS-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/HP-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IAR-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Intel-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/MSVC-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PGI-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PathScale-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SCO-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/TI-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Watcom-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XL-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeFindBinUtils.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-FindBinUtils.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXCompiler.cmake.in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isGenerated" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/3.22.1-g37088a8/CMakeCXXCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeSystemSpecificInformation.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeGenericSystem.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeInitializeConfigs.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/hooks/pre/Android.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Linux.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/UnixPaths.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCInformation.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-C.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GNU.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang-C.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/hooks/pre/Android-Clang.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/flags.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerABI.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitIncludeInfo.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitLinkInfo.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseLibraryArchitecture.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCCompilerABI.c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompileFeatures.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Internal/FeatureTesting.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCCompiler.cmake.in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isGenerated" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/3.22.1-g37088a8/CMakeCCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXInformation.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-CXX.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang-CXX.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCXXCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerABI.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitIncludeInfo.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitLinkInfo.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseLibraryArchitecture.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXCompilerABI.cpp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompileFeatures.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Internal/FeatureTesting.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXCompiler.cmake.in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isGenerated" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/3.22.1-g37088a8/CMakeCXXCompiler.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactCommon/cmake-utils/react-native-flags.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CheckIPOSupported.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CheckIPOSupported/foo.cpp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isCMake" : true,
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CheckIPOSupported/main.cpp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab/lib/i686-linux-android/cmake/ReactAndroid/ReactAndroidConfigVersion.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab/lib/i686-linux-android/cmake/ReactAndroid/ReactAndroidConfig.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab/lib/i686-linux-android/cmake/fbjni/fbjniConfigVersion.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isExternal" : true,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab/lib/i686-linux-android/cmake/fbjni/fbjniConfig.cmake"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind" : "cmakeFiles",
|
||||||
|
"paths" :
|
||||||
|
{
|
||||||
|
"build" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86",
|
||||||
|
"source" : "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup"
|
||||||
|
},
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 1,
|
||||||
|
"minor" : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"configurations" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"directories" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"build" : ".",
|
||||||
|
"jsonFile" : "directory-.-Debug-f5ebdc15457944623624.json",
|
||||||
|
"minimumCMakeVersion" :
|
||||||
|
{
|
||||||
|
"string" : "3.13"
|
||||||
|
},
|
||||||
|
"projectIndex" : 0,
|
||||||
|
"source" : ".",
|
||||||
|
"targetIndexes" :
|
||||||
|
[
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" : "Debug",
|
||||||
|
"projects" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"directoryIndexes" :
|
||||||
|
[
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"name" : "appmodules",
|
||||||
|
"targetIndexes" :
|
||||||
|
[
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"directoryIndex" : 0,
|
||||||
|
"id" : "appmodules::@6890427a1f51a3e7e1df",
|
||||||
|
"jsonFile" : "target-appmodules-Debug-9ef032710fe355da9383.json",
|
||||||
|
"name" : "appmodules",
|
||||||
|
"projectIndex" : 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind" : "codemodel",
|
||||||
|
"paths" :
|
||||||
|
{
|
||||||
|
"build" : "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86",
|
||||||
|
"source" : "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup"
|
||||||
|
},
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 2,
|
||||||
|
"minor" : 3
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"backtraceGraph" :
|
||||||
|
{
|
||||||
|
"commands" : [],
|
||||||
|
"files" : [],
|
||||||
|
"nodes" : []
|
||||||
|
},
|
||||||
|
"installers" : [],
|
||||||
|
"paths" :
|
||||||
|
{
|
||||||
|
"build" : ".",
|
||||||
|
"source" : "."
|
||||||
|
}
|
||||||
|
}
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"cmake" :
|
||||||
|
{
|
||||||
|
"generator" :
|
||||||
|
{
|
||||||
|
"multiConfig" : false,
|
||||||
|
"name" : "Ninja"
|
||||||
|
},
|
||||||
|
"paths" :
|
||||||
|
{
|
||||||
|
"cmake" : "/home/echo/Android/Sdk/cmake/3.22.1/bin/cmake",
|
||||||
|
"cpack" : "/home/echo/Android/Sdk/cmake/3.22.1/bin/cpack",
|
||||||
|
"ctest" : "/home/echo/Android/Sdk/cmake/3.22.1/bin/ctest",
|
||||||
|
"root" : "/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22"
|
||||||
|
},
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"isDirty" : false,
|
||||||
|
"major" : 3,
|
||||||
|
"minor" : 22,
|
||||||
|
"patch" : 1,
|
||||||
|
"string" : "3.22.1-g37088a8",
|
||||||
|
"suffix" : "g37088a8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"objects" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"jsonFile" : "codemodel-v2-d483cb7bfe026ad3a64f.json",
|
||||||
|
"kind" : "codemodel",
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 2,
|
||||||
|
"minor" : 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jsonFile" : "cache-v2-099ee692bdea7ed85643.json",
|
||||||
|
"kind" : "cache",
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 2,
|
||||||
|
"minor" : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jsonFile" : "cmakeFiles-v1-b99aeefcc68e41c89ebf.json",
|
||||||
|
"kind" : "cmakeFiles",
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 1,
|
||||||
|
"minor" : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"reply" :
|
||||||
|
{
|
||||||
|
"client-agp" :
|
||||||
|
{
|
||||||
|
"cache-v2" :
|
||||||
|
{
|
||||||
|
"jsonFile" : "cache-v2-099ee692bdea7ed85643.json",
|
||||||
|
"kind" : "cache",
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 2,
|
||||||
|
"minor" : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cmakeFiles-v1" :
|
||||||
|
{
|
||||||
|
"jsonFile" : "cmakeFiles-v1-b99aeefcc68e41c89ebf.json",
|
||||||
|
"kind" : "cmakeFiles",
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 1,
|
||||||
|
"minor" : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"codemodel-v2" :
|
||||||
|
{
|
||||||
|
"jsonFile" : "codemodel-v2-d483cb7bfe026ad3a64f.json",
|
||||||
|
"kind" : "codemodel",
|
||||||
|
"version" :
|
||||||
|
{
|
||||||
|
"major" : 2,
|
||||||
|
"minor" : 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+226
@@ -0,0 +1,226 @@
|
|||||||
|
{
|
||||||
|
"artifacts" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/build/intermediates/cxx/Debug/2z472e3c/obj/x86/libappmodules.so"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"backtrace" : 3,
|
||||||
|
"backtraceGraph" :
|
||||||
|
{
|
||||||
|
"commands" :
|
||||||
|
[
|
||||||
|
"add_library",
|
||||||
|
"include",
|
||||||
|
"target_link_libraries",
|
||||||
|
"target_compile_options",
|
||||||
|
"target_compile_reactnative_options",
|
||||||
|
"target_compile_definitions",
|
||||||
|
"target_include_directories"
|
||||||
|
],
|
||||||
|
"files" :
|
||||||
|
[
|
||||||
|
"/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake",
|
||||||
|
"CMakeLists.txt",
|
||||||
|
"/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactCommon/cmake-utils/react-native-flags.cmake"
|
||||||
|
],
|
||||||
|
"nodes" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"file" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 1,
|
||||||
|
"file" : 1,
|
||||||
|
"line" : 31,
|
||||||
|
"parent" : 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file" : 0,
|
||||||
|
"parent" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 0,
|
||||||
|
"file" : 0,
|
||||||
|
"line" : 64,
|
||||||
|
"parent" : 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 2,
|
||||||
|
"file" : 0,
|
||||||
|
"line" : 81,
|
||||||
|
"parent" : 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 4,
|
||||||
|
"file" : 0,
|
||||||
|
"line" : 71,
|
||||||
|
"parent" : 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 3,
|
||||||
|
"file" : 2,
|
||||||
|
"line" : 30,
|
||||||
|
"parent" : 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 5,
|
||||||
|
"file" : 2,
|
||||||
|
"line" : 33,
|
||||||
|
"parent" : 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command" : 6,
|
||||||
|
"file" : 0,
|
||||||
|
"line" : 66,
|
||||||
|
"parent" : 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"compileGroups" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"compileCommandFragments" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fragment" : "-g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D__BIONIC_NO_PAGE_SIZE_MACRO -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fno-limit-debug-info -fPIC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-Wall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-Werror"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-fexceptions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-frtti"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-std=c++20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-DFOLLY_NO_CONFIG=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 6,
|
||||||
|
"fragment" : "-DLOG_TAG=\\\"ReactNative\\\""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"defines" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"backtrace" : 7,
|
||||||
|
"define" : "RN_SERIALIZABLE_STATE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"define" : "appmodules_EXPORTS"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"includes" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"backtrace" : 8,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 8,
|
||||||
|
"path" : "/home/echo/dev/prototype/apps/mobile/android/app/build/generated/autolinking/src/main/jni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 4,
|
||||||
|
"isSystem" : true,
|
||||||
|
"path" : "/home/echo/.gradle/caches/8.14.3/transforms/488fe6e480efb97ec75859f6e274282f/transformed/fbjni-0.7.0/prefab/modules/fbjni/include"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 4,
|
||||||
|
"isSystem" : true,
|
||||||
|
"path" : "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/jsi/include"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 4,
|
||||||
|
"isSystem" : true,
|
||||||
|
"path" : "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/reactnative/include"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"language" : "CXX",
|
||||||
|
"sourceIndexes" :
|
||||||
|
[
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"sysroot" :
|
||||||
|
{
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id" : "appmodules::@6890427a1f51a3e7e1df",
|
||||||
|
"link" :
|
||||||
|
{
|
||||||
|
"commandFragments" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fragment" : "-Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--no-undefined-version -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments",
|
||||||
|
"role" : "flags"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 4,
|
||||||
|
"fragment" : "/home/echo/.gradle/caches/8.14.3/transforms/488fe6e480efb97ec75859f6e274282f/transformed/fbjni-0.7.0/prefab/modules/fbjni/libs/android.x86/libfbjni.so",
|
||||||
|
"role" : "libraries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 4,
|
||||||
|
"fragment" : "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/jsi/libs/android.x86/libjsi.so",
|
||||||
|
"role" : "libraries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"backtrace" : 4,
|
||||||
|
"fragment" : "/home/echo/.gradle/caches/8.14.3/transforms/e5d515112484fe4dddc05785469cc380/transformed/react-android-0.81.5-debug/prefab/modules/reactnative/libs/android.x86/libreactnative.so",
|
||||||
|
"role" : "libraries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fragment" : "-latomic -lm",
|
||||||
|
"role" : "libraries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"language" : "CXX",
|
||||||
|
"sysroot" :
|
||||||
|
{
|
||||||
|
"path" : "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "appmodules",
|
||||||
|
"nameOnDisk" : "libappmodules.so",
|
||||||
|
"paths" :
|
||||||
|
{
|
||||||
|
"build" : ".",
|
||||||
|
"source" : "."
|
||||||
|
},
|
||||||
|
"sourceGroups" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name" : "Source Files",
|
||||||
|
"sourceIndexes" :
|
||||||
|
[
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sources" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"backtrace" : 3,
|
||||||
|
"compileGroupIndex" : 0,
|
||||||
|
"path" : "OnLoad.cpp",
|
||||||
|
"sourceGroupIndex" : 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type" : "SHARED_LIBRARY"
|
||||||
|
}
|
||||||
@@ -0,0 +1,420 @@
|
|||||||
|
# This is the CMakeCache file.
|
||||||
|
# For build in directory: /home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86
|
||||||
|
# It was generated by CMake: /home/echo/Android/Sdk/cmake/3.22.1/bin/cmake
|
||||||
|
# You can edit this file to change values found and used by cmake.
|
||||||
|
# If you do not want to change any of the values, simply exit the editor.
|
||||||
|
# If you do want to change a value, simply edit, save, and exit the editor.
|
||||||
|
# The syntax for the file is as follows:
|
||||||
|
# KEY:TYPE=VALUE
|
||||||
|
# KEY is the name of a variable in the cache.
|
||||||
|
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
|
||||||
|
# VALUE is the current value for the KEY.
|
||||||
|
|
||||||
|
########################
|
||||||
|
# EXTERNAL cache entries
|
||||||
|
########################
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
ANDROID_ABI:UNINITIALIZED=x86
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
ANDROID_NDK:UNINITIALIZED=/home/echo/Android/Sdk/ndk/27.1.12297006
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
ANDROID_PLATFORM:UNINITIALIZED=android-26
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
ANDROID_STL:UNINITIALIZED=c++_shared
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES:UNINITIALIZED=ON
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CCACHE_FOUND:FILEPATH=CCACHE_FOUND-NOTFOUND
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_ADDR2LINE:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-addr2line
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_ANDROID_ARCH_ABI:UNINITIALIZED=x86
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_ANDROID_NDK:UNINITIALIZED=/home/echo/Android/Sdk/ndk/27.1.12297006
|
||||||
|
|
||||||
|
//Archiver
|
||||||
|
CMAKE_AR:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
|
||||||
|
|
||||||
|
//Flags used by the compiler during all build types.
|
||||||
|
CMAKE_ASM_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during debug builds.
|
||||||
|
CMAKE_ASM_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during release builds.
|
||||||
|
CMAKE_ASM_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Choose the type of build, options are: None Debug Release RelWithDebInfo
|
||||||
|
// MinSizeRel ...
|
||||||
|
CMAKE_BUILD_TYPE:STRING=Debug
|
||||||
|
|
||||||
|
//LLVM archiver
|
||||||
|
CMAKE_CXX_COMPILER_AR:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
|
||||||
|
|
||||||
|
//Generate index for LLVM archive
|
||||||
|
CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
|
||||||
|
|
||||||
|
//Flags used by the compiler during all build types.
|
||||||
|
CMAKE_CXX_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during debug builds.
|
||||||
|
CMAKE_CXX_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the CXX compiler during MINSIZEREL builds.
|
||||||
|
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
|
||||||
|
|
||||||
|
//Flags used by the compiler during release builds.
|
||||||
|
CMAKE_CXX_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the CXX compiler during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
|
||||||
|
|
||||||
|
//Libraries linked by default with all C++ applications.
|
||||||
|
CMAKE_CXX_STANDARD_LIBRARIES:STRING=-latomic -lm
|
||||||
|
|
||||||
|
//LLVM archiver
|
||||||
|
CMAKE_C_COMPILER_AR:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
|
||||||
|
|
||||||
|
//Generate index for LLVM archive
|
||||||
|
CMAKE_C_COMPILER_RANLIB:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
|
||||||
|
|
||||||
|
//Flags used by the compiler during all build types.
|
||||||
|
CMAKE_C_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during debug builds.
|
||||||
|
CMAKE_C_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the C compiler during MINSIZEREL builds.
|
||||||
|
CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
|
||||||
|
|
||||||
|
//Flags used by the compiler during release builds.
|
||||||
|
CMAKE_C_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the C compiler during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
|
||||||
|
|
||||||
|
//Libraries linked by default with all C applications.
|
||||||
|
CMAKE_C_STANDARD_LIBRARIES:STRING=-latomic -lm
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_DLLTOOL:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-dlltool
|
||||||
|
|
||||||
|
//Flags used by the linker.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during DEBUG builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during MINSIZEREL builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during RELEASE builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_EXPORT_COMPILE_COMMANDS:UNINITIALIZED=ON
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_FIND_ROOT_PATH:UNINITIALIZED=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab
|
||||||
|
|
||||||
|
//Install path prefix, prepended onto install directories.
|
||||||
|
CMAKE_INSTALL_PREFIX:PATH=/usr/local
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_LIBRARY_OUTPUT_DIRECTORY:UNINITIALIZED=/home/echo/dev/prototype/apps/mobile/android/app/build/intermediates/cxx/Debug/2z472e3c/obj/x86
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_LINKER:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_MAKE_PROGRAM:UNINITIALIZED=/home/echo/Android/Sdk/cmake/3.22.1/bin/ninja
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// DEBUG builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// MINSIZEREL builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// RELEASE builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// RELWITHDEBINFO builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_NM:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-nm
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_OBJCOPY:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objcopy
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_OBJDUMP:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objdump
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
CMAKE_PROJECT_DESCRIPTION:STATIC=
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
CMAKE_PROJECT_NAME:STATIC=appmodules
|
||||||
|
|
||||||
|
//Ranlib
|
||||||
|
CMAKE_RANLIB:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
|
||||||
|
|
||||||
|
//Path to a program.
|
||||||
|
CMAKE_READELF:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-readelf
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_RUNTIME_OUTPUT_DIRECTORY:UNINITIALIZED=/home/echo/dev/prototype/apps/mobile/android/app/build/intermediates/cxx/Debug/2z472e3c/obj/x86
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of dll's.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during DEBUG builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during MINSIZEREL builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during RELEASE builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//If set, runtime paths are not added when installing shared libraries,
|
||||||
|
// but are added when building.
|
||||||
|
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
|
||||||
|
|
||||||
|
//If set, runtime paths are not added when using shared libraries.
|
||||||
|
CMAKE_SKIP_RPATH:BOOL=NO
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during all build types.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during DEBUG builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during MINSIZEREL builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during RELEASE builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//Strip
|
||||||
|
CMAKE_STRIP:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_SYSTEM_NAME:UNINITIALIZED=Android
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_SYSTEM_VERSION:UNINITIALIZED=26
|
||||||
|
|
||||||
|
//The CMake toolchain file
|
||||||
|
CMAKE_TOOLCHAIN_FILE:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/android.toolchain.cmake
|
||||||
|
|
||||||
|
//If this value is on, makefiles will be generated without the
|
||||||
|
// .SILENT directive, and all commands will be echoed to the console
|
||||||
|
// during the make. This is useful for debugging only. With Visual
|
||||||
|
// Studio IDE projects all commands are done without /nologo.
|
||||||
|
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
PROJECT_BUILD_DIR:UNINITIALIZED=/home/echo/dev/prototype/apps/mobile/android/app/build
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
PROJECT_ROOT_DIR:UNINITIALIZED=/home/echo/dev/prototype/apps/mobile/android
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
REACT_ANDROID_DIR:UNINITIALIZED=/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid
|
||||||
|
|
||||||
|
//The directory containing a CMake configuration file for ReactAndroid.
|
||||||
|
ReactAndroid_DIR:PATH=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab/lib/i686-linux-android/cmake/ReactAndroid
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
appmodules_BINARY_DIR:STATIC=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
appmodules_IS_TOP_LEVEL:STATIC=ON
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
appmodules_SOURCE_DIR:STATIC=/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup
|
||||||
|
|
||||||
|
//The directory containing a CMake configuration file for fbjni.
|
||||||
|
fbjni_DIR:PATH=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/prefab/x86/prefab/lib/i686-linux-android/cmake/fbjni
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
# INTERNAL cache entries
|
||||||
|
########################
|
||||||
|
|
||||||
|
//ADVANCED property for variable: CMAKE_ADDR2LINE
|
||||||
|
CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_AR
|
||||||
|
CMAKE_AR-ADVANCED:INTERNAL=1
|
||||||
|
//This is the directory where this CMakeCache.txt was created
|
||||||
|
CMAKE_CACHEFILE_DIR:INTERNAL=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86
|
||||||
|
//Major version of cmake used to create the current loaded cache
|
||||||
|
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
|
||||||
|
//Minor version of cmake used to create the current loaded cache
|
||||||
|
CMAKE_CACHE_MINOR_VERSION:INTERNAL=22
|
||||||
|
//Patch version of cmake used to create the current loaded cache
|
||||||
|
CMAKE_CACHE_PATCH_VERSION:INTERNAL=1
|
||||||
|
//Path to CMake executable.
|
||||||
|
CMAKE_COMMAND:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/bin/cmake
|
||||||
|
//Path to cpack program executable.
|
||||||
|
CMAKE_CPACK_COMMAND:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/bin/cpack
|
||||||
|
//Path to ctest program executable.
|
||||||
|
CMAKE_CTEST_COMMAND:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/bin/ctest
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR
|
||||||
|
CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB
|
||||||
|
CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS
|
||||||
|
CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
|
||||||
|
CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
|
||||||
|
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_STANDARD_LIBRARIES
|
||||||
|
CMAKE_CXX_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_COMPILER_AR
|
||||||
|
CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB
|
||||||
|
CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_FLAGS
|
||||||
|
CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
|
||||||
|
CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
|
||||||
|
CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_C_STANDARD_LIBRARIES
|
||||||
|
CMAKE_C_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_DLLTOOL
|
||||||
|
CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
|
||||||
|
//Executable file format
|
||||||
|
CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
|
||||||
|
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//Name of external makefile project generator.
|
||||||
|
CMAKE_EXTRA_GENERATOR:INTERNAL=
|
||||||
|
//Name of generator.
|
||||||
|
CMAKE_GENERATOR:INTERNAL=Ninja
|
||||||
|
//Generator instance identifier.
|
||||||
|
CMAKE_GENERATOR_INSTANCE:INTERNAL=
|
||||||
|
//Name of generator platform.
|
||||||
|
CMAKE_GENERATOR_PLATFORM:INTERNAL=
|
||||||
|
//Name of generator toolset.
|
||||||
|
CMAKE_GENERATOR_TOOLSET:INTERNAL=
|
||||||
|
//Source directory with the top level CMakeLists.txt file for this
|
||||||
|
// project
|
||||||
|
CMAKE_HOME_DIRECTORY:INTERNAL=/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup
|
||||||
|
//Install .so files without execute permission.
|
||||||
|
CMAKE_INSTALL_SO_NO_EXE:INTERNAL=0
|
||||||
|
//ADVANCED property for variable: CMAKE_LINKER
|
||||||
|
CMAKE_LINKER-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_NM
|
||||||
|
CMAKE_NM-ADVANCED:INTERNAL=1
|
||||||
|
//number of local generators
|
||||||
|
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_OBJCOPY
|
||||||
|
CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_OBJDUMP
|
||||||
|
CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
|
||||||
|
//Platform information initialized
|
||||||
|
CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_RANLIB
|
||||||
|
CMAKE_RANLIB-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_READELF
|
||||||
|
CMAKE_READELF-ADVANCED:INTERNAL=1
|
||||||
|
//Path to CMake installation.
|
||||||
|
CMAKE_ROOT:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
|
||||||
|
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SKIP_RPATH
|
||||||
|
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STRIP
|
||||||
|
CMAKE_STRIP-ADVANCED:INTERNAL=1
|
||||||
|
//uname command
|
||||||
|
CMAKE_UNAME:INTERNAL=/usr/bin/uname
|
||||||
|
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
|
||||||
|
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
|
||||||
|
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
set(CMAKE_C_COMPILER "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/clang")
|
||||||
|
set(CMAKE_C_COMPILER_ARG1 "")
|
||||||
|
set(CMAKE_C_COMPILER_ID "Clang")
|
||||||
|
set(CMAKE_C_COMPILER_VERSION "18.0.2")
|
||||||
|
set(CMAKE_C_COMPILER_VERSION_INTERNAL "")
|
||||||
|
set(CMAKE_C_COMPILER_WRAPPER "")
|
||||||
|
set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "17")
|
||||||
|
set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "ON")
|
||||||
|
set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert;c_std_17;c_std_23")
|
||||||
|
set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes")
|
||||||
|
set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros")
|
||||||
|
set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert")
|
||||||
|
set(CMAKE_C17_COMPILE_FEATURES "c_std_17")
|
||||||
|
set(CMAKE_C23_COMPILE_FEATURES "c_std_23")
|
||||||
|
|
||||||
|
set(CMAKE_C_PLATFORM_ID "Linux")
|
||||||
|
set(CMAKE_C_SIMULATE_ID "")
|
||||||
|
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
|
||||||
|
set(CMAKE_C_SIMULATE_VERSION "")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_AR "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
|
||||||
|
set(CMAKE_C_COMPILER_AR "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
|
||||||
|
set(CMAKE_RANLIB "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
|
||||||
|
set(CMAKE_C_COMPILER_RANLIB "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
|
||||||
|
set(CMAKE_LINKER "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld")
|
||||||
|
set(CMAKE_MT "")
|
||||||
|
set(CMAKE_COMPILER_IS_GNUCC )
|
||||||
|
set(CMAKE_C_COMPILER_LOADED 1)
|
||||||
|
set(CMAKE_C_COMPILER_WORKS TRUE)
|
||||||
|
set(CMAKE_C_ABI_COMPILED TRUE)
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER_ENV_VAR "CC")
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER_ID_RUN 1)
|
||||||
|
set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
|
||||||
|
set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
|
||||||
|
set(CMAKE_C_LINKER_PREFERENCE 10)
|
||||||
|
|
||||||
|
# Save compiler ABI information.
|
||||||
|
set(CMAKE_C_SIZEOF_DATA_PTR "4")
|
||||||
|
set(CMAKE_C_COMPILER_ABI "ELF")
|
||||||
|
set(CMAKE_C_BYTE_ORDER "LITTLE_ENDIAN")
|
||||||
|
set(CMAKE_C_LIBRARY_ARCHITECTURE "")
|
||||||
|
|
||||||
|
if(CMAKE_C_SIZEOF_DATA_PTR)
|
||||||
|
set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_C_COMPILER_ABI)
|
||||||
|
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_C_LIBRARY_ARCHITECTURE)
|
||||||
|
set(CMAKE_LIBRARY_ARCHITECTURE "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "")
|
||||||
|
if(CMAKE_C_CL_SHOWINCLUDES_PREFIX)
|
||||||
|
set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/include;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/i686-linux-android;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include")
|
||||||
|
set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "-l:libunwind.a;dl;c;-l:libunwind.a;dl")
|
||||||
|
set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/lib/linux/i386;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/26;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib")
|
||||||
|
set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
|
||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
set(CMAKE_CXX_COMPILER "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++")
|
||||||
|
set(CMAKE_CXX_COMPILER_ARG1 "")
|
||||||
|
set(CMAKE_CXX_COMPILER_ID "Clang")
|
||||||
|
set(CMAKE_CXX_COMPILER_VERSION "18.0.2")
|
||||||
|
set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "")
|
||||||
|
set(CMAKE_CXX_COMPILER_WRAPPER "")
|
||||||
|
set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "17")
|
||||||
|
set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "ON")
|
||||||
|
set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23")
|
||||||
|
set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters")
|
||||||
|
set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
|
||||||
|
set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
|
||||||
|
set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17")
|
||||||
|
set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20")
|
||||||
|
set(CMAKE_CXX23_COMPILE_FEATURES "cxx_std_23")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_PLATFORM_ID "Linux")
|
||||||
|
set(CMAKE_CXX_SIMULATE_ID "")
|
||||||
|
set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")
|
||||||
|
set(CMAKE_CXX_SIMULATE_VERSION "")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_AR "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
|
||||||
|
set(CMAKE_CXX_COMPILER_AR "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
|
||||||
|
set(CMAKE_RANLIB "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
|
||||||
|
set(CMAKE_CXX_COMPILER_RANLIB "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
|
||||||
|
set(CMAKE_LINKER "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld")
|
||||||
|
set(CMAKE_MT "")
|
||||||
|
set(CMAKE_COMPILER_IS_GNUCXX )
|
||||||
|
set(CMAKE_CXX_COMPILER_LOADED 1)
|
||||||
|
set(CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||||
|
set(CMAKE_CXX_ABI_COMPILED TRUE)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_COMPILER_ID_RUN 1)
|
||||||
|
set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm)
|
||||||
|
set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
|
||||||
|
|
||||||
|
foreach (lang C OBJC OBJCXX)
|
||||||
|
if (CMAKE_${lang}_COMPILER_ID_RUN)
|
||||||
|
foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS)
|
||||||
|
list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_LINKER_PREFERENCE 30)
|
||||||
|
set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
|
||||||
|
|
||||||
|
# Save compiler ABI information.
|
||||||
|
set(CMAKE_CXX_SIZEOF_DATA_PTR "4")
|
||||||
|
set(CMAKE_CXX_COMPILER_ABI "ELF")
|
||||||
|
set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN")
|
||||||
|
set(CMAKE_CXX_LIBRARY_ARCHITECTURE "")
|
||||||
|
|
||||||
|
if(CMAKE_CXX_SIZEOF_DATA_PTR)
|
||||||
|
set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ABI)
|
||||||
|
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_CXX_LIBRARY_ARCHITECTURE)
|
||||||
|
set(CMAKE_LIBRARY_ARCHITECTURE "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "")
|
||||||
|
if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX)
|
||||||
|
set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/include;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/i686-linux-android;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include")
|
||||||
|
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "c++;m;-l:libunwind.a;dl;c;-l:libunwind.a;dl")
|
||||||
|
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/lib/linux/i386;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/26;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android;/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib")
|
||||||
|
set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+15
@@ -0,0 +1,15 @@
|
|||||||
|
set(CMAKE_HOST_SYSTEM "Linux-6.17.8-arch1-1")
|
||||||
|
set(CMAKE_HOST_SYSTEM_NAME "Linux")
|
||||||
|
set(CMAKE_HOST_SYSTEM_VERSION "6.17.8-arch1-1")
|
||||||
|
set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")
|
||||||
|
|
||||||
|
include("/home/echo/Android/Sdk/ndk/27.1.12297006/build/cmake/android.toolchain.cmake")
|
||||||
|
|
||||||
|
set(CMAKE_SYSTEM "Android-1")
|
||||||
|
set(CMAKE_SYSTEM_NAME "Android")
|
||||||
|
set(CMAKE_SYSTEM_VERSION "1")
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR "i686")
|
||||||
|
|
||||||
|
set(CMAKE_CROSSCOMPILING "TRUE")
|
||||||
|
|
||||||
|
set(CMAKE_SYSTEM_LOADED 1)
|
||||||
+803
@@ -0,0 +1,803 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
# error "A C++ compiler has been selected for C."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__18CXX)
|
||||||
|
# define ID_VOID_MAIN
|
||||||
|
#endif
|
||||||
|
#if defined(__CLASSIC_C__)
|
||||||
|
/* cv-qualifiers did not exist in K&R C */
|
||||||
|
# define const
|
||||||
|
# define volatile
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__has_include)
|
||||||
|
/* If the compiler does not have __has_include, pretend the answer is
|
||||||
|
always no. */
|
||||||
|
# define __has_include(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Version number components: V=Version, R=Revision, P=Patch
|
||||||
|
Version date components: YYYY=Year, MM=Month, DD=Day */
|
||||||
|
|
||||||
|
#if defined(__INTEL_COMPILER) || defined(__ICC)
|
||||||
|
# define COMPILER_ID "Intel"
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC__)
|
||||||
|
# define SIMULATE_ID "GNU"
|
||||||
|
# endif
|
||||||
|
/* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
|
||||||
|
except that a few beta releases use the old format with V=2021. */
|
||||||
|
# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
|
||||||
|
# if defined(__INTEL_COMPILER_UPDATE)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
|
||||||
|
# else
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10)
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
|
||||||
|
/* The third version component from --version is an update index,
|
||||||
|
but no macro is provided for it. */
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(0)
|
||||||
|
# endif
|
||||||
|
# if defined(__INTEL_COMPILER_BUILD_DATE)
|
||||||
|
/* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
|
||||||
|
# endif
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||||
|
# elif defined(__GNUG__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_MINOR__)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
|
||||||
|
# define COMPILER_ID "IntelLLVM"
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define SIMULATE_ID "GNU"
|
||||||
|
#endif
|
||||||
|
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
|
||||||
|
* later. Look for 6 digit vs. 8 digit version number to decide encoding.
|
||||||
|
* VVVV is no smaller than the current year when a version is released.
|
||||||
|
*/
|
||||||
|
#if __INTEL_LLVM_COMPILER < 1000000L
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10)
|
||||||
|
#else
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100)
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||||
|
#elif defined(__GNUG__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC_MINOR__)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__PATHCC__)
|
||||||
|
# define COMPILER_ID "PathScale"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
|
||||||
|
# if defined(__PATHCC_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
|
||||||
|
# define COMPILER_ID "Embarcadero"
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF)
|
||||||
|
|
||||||
|
#elif defined(__BORLANDC__)
|
||||||
|
# define COMPILER_ID "Borland"
|
||||||
|
/* __BORLANDC__ = 0xVRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
|
||||||
|
# define COMPILER_ID "Watcom"
|
||||||
|
/* __WATCOMC__ = VVRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
|
||||||
|
# if (__WATCOMC__ % 10) > 0
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# define COMPILER_ID "OpenWatcom"
|
||||||
|
/* __WATCOMC__ = VVRP + 1100 */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
|
||||||
|
# if (__WATCOMC__ % 10) > 0
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__SUNPRO_C)
|
||||||
|
# define COMPILER_ID "SunPro"
|
||||||
|
# if __SUNPRO_C >= 0x5100
|
||||||
|
/* __SUNPRO_C = 0xVRRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF)
|
||||||
|
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF)
|
||||||
|
# else
|
||||||
|
/* __SUNPRO_CC = 0xVRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF)
|
||||||
|
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__HP_cc)
|
||||||
|
# define COMPILER_ID "HP"
|
||||||
|
/* __HP_cc = VVRRPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100)
|
||||||
|
|
||||||
|
#elif defined(__DECC)
|
||||||
|
# define COMPILER_ID "Compaq"
|
||||||
|
/* __DECC_VER = VVRRTPPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000)
|
||||||
|
|
||||||
|
#elif defined(__IBMC__) && defined(__COMPILER_VER__)
|
||||||
|
# define COMPILER_ID "zOS"
|
||||||
|
/* __IBMC__ = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
|
||||||
|
|
||||||
|
#elif defined(__ibmxl__) && defined(__clang__)
|
||||||
|
# define COMPILER_ID "XLClang"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800
|
||||||
|
# define COMPILER_ID "XL"
|
||||||
|
/* __IBMC__ = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
|
||||||
|
|
||||||
|
#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800
|
||||||
|
# define COMPILER_ID "VisualAge"
|
||||||
|
/* __IBMC__ = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
|
||||||
|
|
||||||
|
#elif defined(__NVCOMPILER)
|
||||||
|
# define COMPILER_ID "NVHPC"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
|
||||||
|
# if defined(__NVCOMPILER_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__PGI)
|
||||||
|
# define COMPILER_ID "PGI"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
|
||||||
|
# if defined(__PGIC_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_CRAYC)
|
||||||
|
# define COMPILER_ID "Cray"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
|
||||||
|
|
||||||
|
#elif defined(__TI_COMPILER_VERSION__)
|
||||||
|
# define COMPILER_ID "TI"
|
||||||
|
/* __TI_COMPILER_VERSION__ = VVVRRRPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000)
|
||||||
|
|
||||||
|
#elif defined(__CLANG_FUJITSU)
|
||||||
|
# define COMPILER_ID "FujitsuClang"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
|
||||||
|
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__FUJITSU)
|
||||||
|
# define COMPILER_ID "Fujitsu"
|
||||||
|
# if defined(__FCC_version__)
|
||||||
|
# define COMPILER_VERSION __FCC_version__
|
||||||
|
# elif defined(__FCC_major__)
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
|
||||||
|
# endif
|
||||||
|
# if defined(__fcc_version)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
|
||||||
|
# elif defined(__FCC_VERSION)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__ghs__)
|
||||||
|
# define COMPILER_ID "GHS"
|
||||||
|
/* __GHS_VERSION_NUMBER = VVVVRP */
|
||||||
|
# ifdef __GHS_VERSION_NUMBER
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__TINYC__)
|
||||||
|
# define COMPILER_ID "TinyCC"
|
||||||
|
|
||||||
|
#elif defined(__BCC__)
|
||||||
|
# define COMPILER_ID "Bruce"
|
||||||
|
|
||||||
|
#elif defined(__SCO_VERSION__)
|
||||||
|
# define COMPILER_ID "SCO"
|
||||||
|
|
||||||
|
#elif defined(__ARMCC_VERSION) && !defined(__clang__)
|
||||||
|
# define COMPILER_ID "ARMCC"
|
||||||
|
#if __ARMCC_VERSION >= 1000000
|
||||||
|
/* __ARMCC_VERSION = VRRPPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
|
||||||
|
#else
|
||||||
|
/* __ARMCC_VERSION = VRPPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__clang__) && defined(__apple_build_version__)
|
||||||
|
# define COMPILER_ID "AppleClang"
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
# endif
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# endif
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
|
||||||
|
|
||||||
|
#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
|
||||||
|
# define COMPILER_ID "ARMClang"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
|
||||||
|
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# define COMPILER_ID "Clang"
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
# endif
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define COMPILER_ID "GNU"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
|
||||||
|
# if defined(__GNUC_MINOR__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define COMPILER_ID "MSVC"
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# if defined(_MSC_FULL_VER)
|
||||||
|
# if _MSC_VER >= 1400
|
||||||
|
/* _MSC_FULL_VER = VVRRPPPPP */
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
|
||||||
|
# else
|
||||||
|
/* _MSC_FULL_VER = VVRRPPPP */
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if defined(_MSC_BUILD)
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
|
||||||
|
# define COMPILER_ID "ADSP"
|
||||||
|
#if defined(__VISUALDSPVERSION__)
|
||||||
|
/* __VISUALDSPVERSION__ = 0xVVRRPP00 */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
|
||||||
|
# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
|
||||||
|
# define COMPILER_ID "IAR"
|
||||||
|
# if defined(__VER__) && defined(__ICCARM__)
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
|
||||||
|
# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC)
|
||||||
|
# define COMPILER_ID "SDCC"
|
||||||
|
# if defined(__SDCC_VERSION_MAJOR)
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH)
|
||||||
|
# else
|
||||||
|
/* SDCC = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(SDCC/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(SDCC % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
/* These compilers are either not known or too old to define an
|
||||||
|
identification macro. Try to identify the platform and guess that
|
||||||
|
it is the native compiler. */
|
||||||
|
#elif defined(__hpux) || defined(__hpua)
|
||||||
|
# define COMPILER_ID "HP"
|
||||||
|
|
||||||
|
#else /* unknown compiler */
|
||||||
|
# define COMPILER_ID ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct the string literal in pieces to prevent the source from
|
||||||
|
getting matched. Store it in a pointer rather than an array
|
||||||
|
because some compilers will just produce instructions to fill the
|
||||||
|
array rather than assigning a pointer to a static array. */
|
||||||
|
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
|
||||||
|
#ifdef SIMULATE_ID
|
||||||
|
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __QNXNTO__
|
||||||
|
char const* qnxnto = "INFO" ":" "qnxnto[]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
|
||||||
|
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRINGIFY_HELPER(X) #X
|
||||||
|
#define STRINGIFY(X) STRINGIFY_HELPER(X)
|
||||||
|
|
||||||
|
/* Identify known platforms by name. */
|
||||||
|
#if defined(__linux) || defined(__linux__) || defined(linux)
|
||||||
|
# define PLATFORM_ID "Linux"
|
||||||
|
|
||||||
|
#elif defined(__MSYS__)
|
||||||
|
# define PLATFORM_ID "MSYS"
|
||||||
|
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
# define PLATFORM_ID "Cygwin"
|
||||||
|
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
# define PLATFORM_ID "MinGW"
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# define PLATFORM_ID "Darwin"
|
||||||
|
|
||||||
|
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||||
|
# define PLATFORM_ID "Windows"
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD)
|
||||||
|
# define PLATFORM_ID "FreeBSD"
|
||||||
|
|
||||||
|
#elif defined(__NetBSD__) || defined(__NetBSD)
|
||||||
|
# define PLATFORM_ID "NetBSD"
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__) || defined(__OPENBSD)
|
||||||
|
# define PLATFORM_ID "OpenBSD"
|
||||||
|
|
||||||
|
#elif defined(__sun) || defined(sun)
|
||||||
|
# define PLATFORM_ID "SunOS"
|
||||||
|
|
||||||
|
#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
|
||||||
|
# define PLATFORM_ID "AIX"
|
||||||
|
|
||||||
|
#elif defined(__hpux) || defined(__hpux__)
|
||||||
|
# define PLATFORM_ID "HP-UX"
|
||||||
|
|
||||||
|
#elif defined(__HAIKU__)
|
||||||
|
# define PLATFORM_ID "Haiku"
|
||||||
|
|
||||||
|
#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
|
||||||
|
# define PLATFORM_ID "BeOS"
|
||||||
|
|
||||||
|
#elif defined(__QNX__) || defined(__QNXNTO__)
|
||||||
|
# define PLATFORM_ID "QNX"
|
||||||
|
|
||||||
|
#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
|
||||||
|
# define PLATFORM_ID "Tru64"
|
||||||
|
|
||||||
|
#elif defined(__riscos) || defined(__riscos__)
|
||||||
|
# define PLATFORM_ID "RISCos"
|
||||||
|
|
||||||
|
#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
|
||||||
|
# define PLATFORM_ID "SINIX"
|
||||||
|
|
||||||
|
#elif defined(__UNIX_SV__)
|
||||||
|
# define PLATFORM_ID "UNIX_SV"
|
||||||
|
|
||||||
|
#elif defined(__bsdos__)
|
||||||
|
# define PLATFORM_ID "BSDOS"
|
||||||
|
|
||||||
|
#elif defined(_MPRAS) || defined(MPRAS)
|
||||||
|
# define PLATFORM_ID "MP-RAS"
|
||||||
|
|
||||||
|
#elif defined(__osf) || defined(__osf__)
|
||||||
|
# define PLATFORM_ID "OSF1"
|
||||||
|
|
||||||
|
#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
|
||||||
|
# define PLATFORM_ID "SCO_SV"
|
||||||
|
|
||||||
|
#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
|
||||||
|
# define PLATFORM_ID "ULTRIX"
|
||||||
|
|
||||||
|
#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
|
||||||
|
# define PLATFORM_ID "Xenix"
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# if defined(__LINUX__)
|
||||||
|
# define PLATFORM_ID "Linux"
|
||||||
|
|
||||||
|
# elif defined(__DOS__)
|
||||||
|
# define PLATFORM_ID "DOS"
|
||||||
|
|
||||||
|
# elif defined(__OS2__)
|
||||||
|
# define PLATFORM_ID "OS2"
|
||||||
|
|
||||||
|
# elif defined(__WINDOWS__)
|
||||||
|
# define PLATFORM_ID "Windows3x"
|
||||||
|
|
||||||
|
# elif defined(__VXWORKS__)
|
||||||
|
# define PLATFORM_ID "VxWorks"
|
||||||
|
|
||||||
|
# else /* unknown platform */
|
||||||
|
# define PLATFORM_ID
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__INTEGRITY)
|
||||||
|
# if defined(INT_178B)
|
||||||
|
# define PLATFORM_ID "Integrity178"
|
||||||
|
|
||||||
|
# else /* regular Integrity */
|
||||||
|
# define PLATFORM_ID "Integrity"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else /* unknown platform */
|
||||||
|
# define PLATFORM_ID
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For windows compilers MSVC and Intel we can determine
|
||||||
|
the architecture of the compiler being used. This is because
|
||||||
|
the compilers do not have flags that can change the architecture,
|
||||||
|
but rather depend on which compiler is being used
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
# if defined(_M_IA64)
|
||||||
|
# define ARCHITECTURE_ID "IA64"
|
||||||
|
|
||||||
|
# elif defined(_M_ARM64EC)
|
||||||
|
# define ARCHITECTURE_ID "ARM64EC"
|
||||||
|
|
||||||
|
# elif defined(_M_X64) || defined(_M_AMD64)
|
||||||
|
# define ARCHITECTURE_ID "x64"
|
||||||
|
|
||||||
|
# elif defined(_M_IX86)
|
||||||
|
# define ARCHITECTURE_ID "X86"
|
||||||
|
|
||||||
|
# elif defined(_M_ARM64)
|
||||||
|
# define ARCHITECTURE_ID "ARM64"
|
||||||
|
|
||||||
|
# elif defined(_M_ARM)
|
||||||
|
# if _M_ARM == 4
|
||||||
|
# define ARCHITECTURE_ID "ARMV4I"
|
||||||
|
# elif _M_ARM == 5
|
||||||
|
# define ARCHITECTURE_ID "ARMV5I"
|
||||||
|
# else
|
||||||
|
# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(_M_MIPS)
|
||||||
|
# define ARCHITECTURE_ID "MIPS"
|
||||||
|
|
||||||
|
# elif defined(_M_SH)
|
||||||
|
# define ARCHITECTURE_ID "SHx"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# if defined(_M_I86)
|
||||||
|
# define ARCHITECTURE_ID "I86"
|
||||||
|
|
||||||
|
# elif defined(_M_IX86)
|
||||||
|
# define ARCHITECTURE_ID "X86"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
|
||||||
|
# if defined(__ICCARM__)
|
||||||
|
# define ARCHITECTURE_ID "ARM"
|
||||||
|
|
||||||
|
# elif defined(__ICCRX__)
|
||||||
|
# define ARCHITECTURE_ID "RX"
|
||||||
|
|
||||||
|
# elif defined(__ICCRH850__)
|
||||||
|
# define ARCHITECTURE_ID "RH850"
|
||||||
|
|
||||||
|
# elif defined(__ICCRL78__)
|
||||||
|
# define ARCHITECTURE_ID "RL78"
|
||||||
|
|
||||||
|
# elif defined(__ICCRISCV__)
|
||||||
|
# define ARCHITECTURE_ID "RISCV"
|
||||||
|
|
||||||
|
# elif defined(__ICCAVR__)
|
||||||
|
# define ARCHITECTURE_ID "AVR"
|
||||||
|
|
||||||
|
# elif defined(__ICC430__)
|
||||||
|
# define ARCHITECTURE_ID "MSP430"
|
||||||
|
|
||||||
|
# elif defined(__ICCV850__)
|
||||||
|
# define ARCHITECTURE_ID "V850"
|
||||||
|
|
||||||
|
# elif defined(__ICC8051__)
|
||||||
|
# define ARCHITECTURE_ID "8051"
|
||||||
|
|
||||||
|
# elif defined(__ICCSTM8__)
|
||||||
|
# define ARCHITECTURE_ID "STM8"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__ghs__)
|
||||||
|
# if defined(__PPC64__)
|
||||||
|
# define ARCHITECTURE_ID "PPC64"
|
||||||
|
|
||||||
|
# elif defined(__ppc__)
|
||||||
|
# define ARCHITECTURE_ID "PPC"
|
||||||
|
|
||||||
|
# elif defined(__ARM__)
|
||||||
|
# define ARCHITECTURE_ID "ARM"
|
||||||
|
|
||||||
|
# elif defined(__x86_64__)
|
||||||
|
# define ARCHITECTURE_ID "x64"
|
||||||
|
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define ARCHITECTURE_ID "X86"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__TI_COMPILER_VERSION__)
|
||||||
|
# if defined(__TI_ARM__)
|
||||||
|
# define ARCHITECTURE_ID "ARM"
|
||||||
|
|
||||||
|
# elif defined(__MSP430__)
|
||||||
|
# define ARCHITECTURE_ID "MSP430"
|
||||||
|
|
||||||
|
# elif defined(__TMS320C28XX__)
|
||||||
|
# define ARCHITECTURE_ID "TMS320C28x"
|
||||||
|
|
||||||
|
# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
|
||||||
|
# define ARCHITECTURE_ID "TMS320C6x"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define ARCHITECTURE_ID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Convert integer to decimal digit literals. */
|
||||||
|
#define DEC(n) \
|
||||||
|
('0' + (((n) / 10000000)%10)), \
|
||||||
|
('0' + (((n) / 1000000)%10)), \
|
||||||
|
('0' + (((n) / 100000)%10)), \
|
||||||
|
('0' + (((n) / 10000)%10)), \
|
||||||
|
('0' + (((n) / 1000)%10)), \
|
||||||
|
('0' + (((n) / 100)%10)), \
|
||||||
|
('0' + (((n) / 10)%10)), \
|
||||||
|
('0' + ((n) % 10))
|
||||||
|
|
||||||
|
/* Convert integer to hex digit literals. */
|
||||||
|
#define HEX(n) \
|
||||||
|
('0' + ((n)>>28 & 0xF)), \
|
||||||
|
('0' + ((n)>>24 & 0xF)), \
|
||||||
|
('0' + ((n)>>20 & 0xF)), \
|
||||||
|
('0' + ((n)>>16 & 0xF)), \
|
||||||
|
('0' + ((n)>>12 & 0xF)), \
|
||||||
|
('0' + ((n)>>8 & 0xF)), \
|
||||||
|
('0' + ((n)>>4 & 0xF)), \
|
||||||
|
('0' + ((n) & 0xF))
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the version number. */
|
||||||
|
#ifdef COMPILER_VERSION
|
||||||
|
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the version number components. */
|
||||||
|
#elif defined(COMPILER_VERSION_MAJOR)
|
||||||
|
char const info_version[] = {
|
||||||
|
'I', 'N', 'F', 'O', ':',
|
||||||
|
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
|
||||||
|
COMPILER_VERSION_MAJOR,
|
||||||
|
# ifdef COMPILER_VERSION_MINOR
|
||||||
|
'.', COMPILER_VERSION_MINOR,
|
||||||
|
# ifdef COMPILER_VERSION_PATCH
|
||||||
|
'.', COMPILER_VERSION_PATCH,
|
||||||
|
# ifdef COMPILER_VERSION_TWEAK
|
||||||
|
'.', COMPILER_VERSION_TWEAK,
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
']','\0'};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the internal version number. */
|
||||||
|
#ifdef COMPILER_VERSION_INTERNAL
|
||||||
|
char const info_version_internal[] = {
|
||||||
|
'I', 'N', 'F', 'O', ':',
|
||||||
|
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
|
||||||
|
'i','n','t','e','r','n','a','l','[',
|
||||||
|
COMPILER_VERSION_INTERNAL,']','\0'};
|
||||||
|
#elif defined(COMPILER_VERSION_INTERNAL_STR)
|
||||||
|
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the version number components. */
|
||||||
|
#ifdef SIMULATE_VERSION_MAJOR
|
||||||
|
char const info_simulate_version[] = {
|
||||||
|
'I', 'N', 'F', 'O', ':',
|
||||||
|
's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
|
||||||
|
SIMULATE_VERSION_MAJOR,
|
||||||
|
# ifdef SIMULATE_VERSION_MINOR
|
||||||
|
'.', SIMULATE_VERSION_MINOR,
|
||||||
|
# ifdef SIMULATE_VERSION_PATCH
|
||||||
|
'.', SIMULATE_VERSION_PATCH,
|
||||||
|
# ifdef SIMULATE_VERSION_TWEAK
|
||||||
|
'.', SIMULATE_VERSION_TWEAK,
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
']','\0'};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct the string literal in pieces to prevent the source from
|
||||||
|
getting matched. Store it in a pointer rather than an array
|
||||||
|
because some compilers will just produce instructions to fill the
|
||||||
|
array rather than assigning a pointer to a static array. */
|
||||||
|
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
|
||||||
|
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(__STDC__) && !defined(__clang__)
|
||||||
|
# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
|
||||||
|
# define C_VERSION "90"
|
||||||
|
# else
|
||||||
|
# define C_VERSION
|
||||||
|
# endif
|
||||||
|
#elif __STDC_VERSION__ > 201710L
|
||||||
|
# define C_VERSION "23"
|
||||||
|
#elif __STDC_VERSION__ >= 201710L
|
||||||
|
# define C_VERSION "17"
|
||||||
|
#elif __STDC_VERSION__ >= 201000L
|
||||||
|
# define C_VERSION "11"
|
||||||
|
#elif __STDC_VERSION__ >= 199901L
|
||||||
|
# define C_VERSION "99"
|
||||||
|
#else
|
||||||
|
# define C_VERSION "90"
|
||||||
|
#endif
|
||||||
|
const char* info_language_standard_default =
|
||||||
|
"INFO" ":" "standard_default[" C_VERSION "]";
|
||||||
|
|
||||||
|
const char* info_language_extensions_default = "INFO" ":" "extensions_default["
|
||||||
|
/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */
|
||||||
|
#if (defined(__clang__) || defined(__GNUC__) || \
|
||||||
|
defined(__TI_COMPILER_VERSION__)) && \
|
||||||
|
!defined(__STRICT_ANSI__) && !defined(_MSC_VER)
|
||||||
|
"ON"
|
||||||
|
#else
|
||||||
|
"OFF"
|
||||||
|
#endif
|
||||||
|
"]";
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifdef ID_VOID_MAIN
|
||||||
|
void main() {}
|
||||||
|
#else
|
||||||
|
# if defined(__CLASSIC_C__)
|
||||||
|
int main(argc, argv) int argc; char *argv[];
|
||||||
|
# else
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
int require = 0;
|
||||||
|
require += info_compiler[argc];
|
||||||
|
require += info_platform[argc];
|
||||||
|
require += info_arch[argc];
|
||||||
|
#ifdef COMPILER_VERSION_MAJOR
|
||||||
|
require += info_version[argc];
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILER_VERSION_INTERNAL
|
||||||
|
require += info_version_internal[argc];
|
||||||
|
#endif
|
||||||
|
#ifdef SIMULATE_ID
|
||||||
|
require += info_simulate[argc];
|
||||||
|
#endif
|
||||||
|
#ifdef SIMULATE_VERSION_MAJOR
|
||||||
|
require += info_simulate_version[argc];
|
||||||
|
#endif
|
||||||
|
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
|
||||||
|
require += info_cray[argc];
|
||||||
|
#endif
|
||||||
|
require += info_language_standard_default[argc];
|
||||||
|
require += info_language_extensions_default[argc];
|
||||||
|
(void)argv;
|
||||||
|
return require;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
BIN
Binary file not shown.
+791
@@ -0,0 +1,791 @@
|
|||||||
|
/* This source file must have a .cpp extension so that all C++ compilers
|
||||||
|
recognize the extension without flags. Borland does not know .cxx for
|
||||||
|
example. */
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error "A C compiler has been selected for C++."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__has_include)
|
||||||
|
/* If the compiler does not have __has_include, pretend the answer is
|
||||||
|
always no. */
|
||||||
|
# define __has_include(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Version number components: V=Version, R=Revision, P=Patch
|
||||||
|
Version date components: YYYY=Year, MM=Month, DD=Day */
|
||||||
|
|
||||||
|
#if defined(__COMO__)
|
||||||
|
# define COMPILER_ID "Comeau"
|
||||||
|
/* __COMO_VERSION__ = VRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100)
|
||||||
|
|
||||||
|
#elif defined(__INTEL_COMPILER) || defined(__ICC)
|
||||||
|
# define COMPILER_ID "Intel"
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC__)
|
||||||
|
# define SIMULATE_ID "GNU"
|
||||||
|
# endif
|
||||||
|
/* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
|
||||||
|
except that a few beta releases use the old format with V=2021. */
|
||||||
|
# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
|
||||||
|
# if defined(__INTEL_COMPILER_UPDATE)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
|
||||||
|
# else
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10)
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
|
||||||
|
/* The third version component from --version is an update index,
|
||||||
|
but no macro is provided for it. */
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(0)
|
||||||
|
# endif
|
||||||
|
# if defined(__INTEL_COMPILER_BUILD_DATE)
|
||||||
|
/* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
|
||||||
|
# endif
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||||
|
# elif defined(__GNUG__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_MINOR__)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
|
||||||
|
# define COMPILER_ID "IntelLLVM"
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define SIMULATE_ID "GNU"
|
||||||
|
#endif
|
||||||
|
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
|
||||||
|
* later. Look for 6 digit vs. 8 digit version number to decide encoding.
|
||||||
|
* VVVV is no smaller than the current year when a version is released.
|
||||||
|
*/
|
||||||
|
#if __INTEL_LLVM_COMPILER < 1000000L
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10)
|
||||||
|
#else
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100)
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||||
|
#elif defined(__GNUG__)
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC_MINOR__)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__PATHCC__)
|
||||||
|
# define COMPILER_ID "PathScale"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
|
||||||
|
# if defined(__PATHCC_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
|
||||||
|
# define COMPILER_ID "Embarcadero"
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF)
|
||||||
|
|
||||||
|
#elif defined(__BORLANDC__)
|
||||||
|
# define COMPILER_ID "Borland"
|
||||||
|
/* __BORLANDC__ = 0xVRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
|
||||||
|
# define COMPILER_ID "Watcom"
|
||||||
|
/* __WATCOMC__ = VVRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
|
||||||
|
# if (__WATCOMC__ % 10) > 0
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# define COMPILER_ID "OpenWatcom"
|
||||||
|
/* __WATCOMC__ = VVRP + 1100 */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
|
||||||
|
# if (__WATCOMC__ % 10) > 0
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__SUNPRO_CC)
|
||||||
|
# define COMPILER_ID "SunPro"
|
||||||
|
# if __SUNPRO_CC >= 0x5100
|
||||||
|
/* __SUNPRO_CC = 0xVRRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF)
|
||||||
|
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF)
|
||||||
|
# else
|
||||||
|
/* __SUNPRO_CC = 0xVRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF)
|
||||||
|
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__HP_aCC)
|
||||||
|
# define COMPILER_ID "HP"
|
||||||
|
/* __HP_aCC = VVRRPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100)
|
||||||
|
|
||||||
|
#elif defined(__DECCXX)
|
||||||
|
# define COMPILER_ID "Compaq"
|
||||||
|
/* __DECCXX_VER = VVRRTPPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000)
|
||||||
|
|
||||||
|
#elif defined(__IBMCPP__) && defined(__COMPILER_VER__)
|
||||||
|
# define COMPILER_ID "zOS"
|
||||||
|
/* __IBMCPP__ = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
|
||||||
|
|
||||||
|
#elif defined(__ibmxl__) && defined(__clang__)
|
||||||
|
# define COMPILER_ID "XLClang"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800
|
||||||
|
# define COMPILER_ID "XL"
|
||||||
|
/* __IBMCPP__ = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
|
||||||
|
|
||||||
|
#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800
|
||||||
|
# define COMPILER_ID "VisualAge"
|
||||||
|
/* __IBMCPP__ = VRP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
|
||||||
|
|
||||||
|
#elif defined(__NVCOMPILER)
|
||||||
|
# define COMPILER_ID "NVHPC"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
|
||||||
|
# if defined(__NVCOMPILER_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__PGI)
|
||||||
|
# define COMPILER_ID "PGI"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
|
||||||
|
# if defined(__PGIC_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_CRAYC)
|
||||||
|
# define COMPILER_ID "Cray"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
|
||||||
|
|
||||||
|
#elif defined(__TI_COMPILER_VERSION__)
|
||||||
|
# define COMPILER_ID "TI"
|
||||||
|
/* __TI_COMPILER_VERSION__ = VVVRRRPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000)
|
||||||
|
|
||||||
|
#elif defined(__CLANG_FUJITSU)
|
||||||
|
# define COMPILER_ID "FujitsuClang"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
|
||||||
|
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__FUJITSU)
|
||||||
|
# define COMPILER_ID "Fujitsu"
|
||||||
|
# if defined(__FCC_version__)
|
||||||
|
# define COMPILER_VERSION __FCC_version__
|
||||||
|
# elif defined(__FCC_major__)
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
|
||||||
|
# endif
|
||||||
|
# if defined(__fcc_version)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
|
||||||
|
# elif defined(__FCC_VERSION)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__ghs__)
|
||||||
|
# define COMPILER_ID "GHS"
|
||||||
|
/* __GHS_VERSION_NUMBER = VVVVRP */
|
||||||
|
# ifdef __GHS_VERSION_NUMBER
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__SCO_VERSION__)
|
||||||
|
# define COMPILER_ID "SCO"
|
||||||
|
|
||||||
|
#elif defined(__ARMCC_VERSION) && !defined(__clang__)
|
||||||
|
# define COMPILER_ID "ARMCC"
|
||||||
|
#if __ARMCC_VERSION >= 1000000
|
||||||
|
/* __ARMCC_VERSION = VRRPPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
|
||||||
|
#else
|
||||||
|
/* __ARMCC_VERSION = VRPPPP */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__clang__) && defined(__apple_build_version__)
|
||||||
|
# define COMPILER_ID "AppleClang"
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
# endif
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# endif
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
|
||||||
|
|
||||||
|
#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
|
||||||
|
# define COMPILER_ID "ARMClang"
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
|
||||||
|
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# define COMPILER_ID "Clang"
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define SIMULATE_ID "MSVC"
|
||||||
|
# endif
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
# define COMPILER_ID "GNU"
|
||||||
|
# if defined(__GNUC__)
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
|
||||||
|
# else
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(__GNUG__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_MINOR__)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||||
|
# endif
|
||||||
|
# if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define COMPILER_ID "MSVC"
|
||||||
|
/* _MSC_VER = VVRR */
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||||
|
# if defined(_MSC_FULL_VER)
|
||||||
|
# if _MSC_VER >= 1400
|
||||||
|
/* _MSC_FULL_VER = VVRRPPPPP */
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
|
||||||
|
# else
|
||||||
|
/* _MSC_FULL_VER = VVRRPPPP */
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if defined(_MSC_BUILD)
|
||||||
|
# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
|
||||||
|
# define COMPILER_ID "ADSP"
|
||||||
|
#if defined(__VISUALDSPVERSION__)
|
||||||
|
/* __VISUALDSPVERSION__ = 0xVVRRPP00 */
|
||||||
|
# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
|
||||||
|
# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
|
||||||
|
# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
|
||||||
|
# define COMPILER_ID "IAR"
|
||||||
|
# if defined(__VER__) && defined(__ICCARM__)
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
|
||||||
|
# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
|
||||||
|
# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
|
||||||
|
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
|
||||||
|
# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
|
||||||
|
# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
|
||||||
|
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
/* These compilers are either not known or too old to define an
|
||||||
|
identification macro. Try to identify the platform and guess that
|
||||||
|
it is the native compiler. */
|
||||||
|
#elif defined(__hpux) || defined(__hpua)
|
||||||
|
# define COMPILER_ID "HP"
|
||||||
|
|
||||||
|
#else /* unknown compiler */
|
||||||
|
# define COMPILER_ID ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct the string literal in pieces to prevent the source from
|
||||||
|
getting matched. Store it in a pointer rather than an array
|
||||||
|
because some compilers will just produce instructions to fill the
|
||||||
|
array rather than assigning a pointer to a static array. */
|
||||||
|
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
|
||||||
|
#ifdef SIMULATE_ID
|
||||||
|
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __QNXNTO__
|
||||||
|
char const* qnxnto = "INFO" ":" "qnxnto[]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
|
||||||
|
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRINGIFY_HELPER(X) #X
|
||||||
|
#define STRINGIFY(X) STRINGIFY_HELPER(X)
|
||||||
|
|
||||||
|
/* Identify known platforms by name. */
|
||||||
|
#if defined(__linux) || defined(__linux__) || defined(linux)
|
||||||
|
# define PLATFORM_ID "Linux"
|
||||||
|
|
||||||
|
#elif defined(__MSYS__)
|
||||||
|
# define PLATFORM_ID "MSYS"
|
||||||
|
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
# define PLATFORM_ID "Cygwin"
|
||||||
|
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
# define PLATFORM_ID "MinGW"
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# define PLATFORM_ID "Darwin"
|
||||||
|
|
||||||
|
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||||
|
# define PLATFORM_ID "Windows"
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD)
|
||||||
|
# define PLATFORM_ID "FreeBSD"
|
||||||
|
|
||||||
|
#elif defined(__NetBSD__) || defined(__NetBSD)
|
||||||
|
# define PLATFORM_ID "NetBSD"
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__) || defined(__OPENBSD)
|
||||||
|
# define PLATFORM_ID "OpenBSD"
|
||||||
|
|
||||||
|
#elif defined(__sun) || defined(sun)
|
||||||
|
# define PLATFORM_ID "SunOS"
|
||||||
|
|
||||||
|
#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
|
||||||
|
# define PLATFORM_ID "AIX"
|
||||||
|
|
||||||
|
#elif defined(__hpux) || defined(__hpux__)
|
||||||
|
# define PLATFORM_ID "HP-UX"
|
||||||
|
|
||||||
|
#elif defined(__HAIKU__)
|
||||||
|
# define PLATFORM_ID "Haiku"
|
||||||
|
|
||||||
|
#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
|
||||||
|
# define PLATFORM_ID "BeOS"
|
||||||
|
|
||||||
|
#elif defined(__QNX__) || defined(__QNXNTO__)
|
||||||
|
# define PLATFORM_ID "QNX"
|
||||||
|
|
||||||
|
#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
|
||||||
|
# define PLATFORM_ID "Tru64"
|
||||||
|
|
||||||
|
#elif defined(__riscos) || defined(__riscos__)
|
||||||
|
# define PLATFORM_ID "RISCos"
|
||||||
|
|
||||||
|
#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
|
||||||
|
# define PLATFORM_ID "SINIX"
|
||||||
|
|
||||||
|
#elif defined(__UNIX_SV__)
|
||||||
|
# define PLATFORM_ID "UNIX_SV"
|
||||||
|
|
||||||
|
#elif defined(__bsdos__)
|
||||||
|
# define PLATFORM_ID "BSDOS"
|
||||||
|
|
||||||
|
#elif defined(_MPRAS) || defined(MPRAS)
|
||||||
|
# define PLATFORM_ID "MP-RAS"
|
||||||
|
|
||||||
|
#elif defined(__osf) || defined(__osf__)
|
||||||
|
# define PLATFORM_ID "OSF1"
|
||||||
|
|
||||||
|
#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
|
||||||
|
# define PLATFORM_ID "SCO_SV"
|
||||||
|
|
||||||
|
#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
|
||||||
|
# define PLATFORM_ID "ULTRIX"
|
||||||
|
|
||||||
|
#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
|
||||||
|
# define PLATFORM_ID "Xenix"
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# if defined(__LINUX__)
|
||||||
|
# define PLATFORM_ID "Linux"
|
||||||
|
|
||||||
|
# elif defined(__DOS__)
|
||||||
|
# define PLATFORM_ID "DOS"
|
||||||
|
|
||||||
|
# elif defined(__OS2__)
|
||||||
|
# define PLATFORM_ID "OS2"
|
||||||
|
|
||||||
|
# elif defined(__WINDOWS__)
|
||||||
|
# define PLATFORM_ID "Windows3x"
|
||||||
|
|
||||||
|
# elif defined(__VXWORKS__)
|
||||||
|
# define PLATFORM_ID "VxWorks"
|
||||||
|
|
||||||
|
# else /* unknown platform */
|
||||||
|
# define PLATFORM_ID
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__INTEGRITY)
|
||||||
|
# if defined(INT_178B)
|
||||||
|
# define PLATFORM_ID "Integrity178"
|
||||||
|
|
||||||
|
# else /* regular Integrity */
|
||||||
|
# define PLATFORM_ID "Integrity"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else /* unknown platform */
|
||||||
|
# define PLATFORM_ID
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For windows compilers MSVC and Intel we can determine
|
||||||
|
the architecture of the compiler being used. This is because
|
||||||
|
the compilers do not have flags that can change the architecture,
|
||||||
|
but rather depend on which compiler is being used
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
# if defined(_M_IA64)
|
||||||
|
# define ARCHITECTURE_ID "IA64"
|
||||||
|
|
||||||
|
# elif defined(_M_ARM64EC)
|
||||||
|
# define ARCHITECTURE_ID "ARM64EC"
|
||||||
|
|
||||||
|
# elif defined(_M_X64) || defined(_M_AMD64)
|
||||||
|
# define ARCHITECTURE_ID "x64"
|
||||||
|
|
||||||
|
# elif defined(_M_IX86)
|
||||||
|
# define ARCHITECTURE_ID "X86"
|
||||||
|
|
||||||
|
# elif defined(_M_ARM64)
|
||||||
|
# define ARCHITECTURE_ID "ARM64"
|
||||||
|
|
||||||
|
# elif defined(_M_ARM)
|
||||||
|
# if _M_ARM == 4
|
||||||
|
# define ARCHITECTURE_ID "ARMV4I"
|
||||||
|
# elif _M_ARM == 5
|
||||||
|
# define ARCHITECTURE_ID "ARMV5I"
|
||||||
|
# else
|
||||||
|
# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(_M_MIPS)
|
||||||
|
# define ARCHITECTURE_ID "MIPS"
|
||||||
|
|
||||||
|
# elif defined(_M_SH)
|
||||||
|
# define ARCHITECTURE_ID "SHx"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# if defined(_M_I86)
|
||||||
|
# define ARCHITECTURE_ID "I86"
|
||||||
|
|
||||||
|
# elif defined(_M_IX86)
|
||||||
|
# define ARCHITECTURE_ID "X86"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
|
||||||
|
# if defined(__ICCARM__)
|
||||||
|
# define ARCHITECTURE_ID "ARM"
|
||||||
|
|
||||||
|
# elif defined(__ICCRX__)
|
||||||
|
# define ARCHITECTURE_ID "RX"
|
||||||
|
|
||||||
|
# elif defined(__ICCRH850__)
|
||||||
|
# define ARCHITECTURE_ID "RH850"
|
||||||
|
|
||||||
|
# elif defined(__ICCRL78__)
|
||||||
|
# define ARCHITECTURE_ID "RL78"
|
||||||
|
|
||||||
|
# elif defined(__ICCRISCV__)
|
||||||
|
# define ARCHITECTURE_ID "RISCV"
|
||||||
|
|
||||||
|
# elif defined(__ICCAVR__)
|
||||||
|
# define ARCHITECTURE_ID "AVR"
|
||||||
|
|
||||||
|
# elif defined(__ICC430__)
|
||||||
|
# define ARCHITECTURE_ID "MSP430"
|
||||||
|
|
||||||
|
# elif defined(__ICCV850__)
|
||||||
|
# define ARCHITECTURE_ID "V850"
|
||||||
|
|
||||||
|
# elif defined(__ICC8051__)
|
||||||
|
# define ARCHITECTURE_ID "8051"
|
||||||
|
|
||||||
|
# elif defined(__ICCSTM8__)
|
||||||
|
# define ARCHITECTURE_ID "STM8"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__ghs__)
|
||||||
|
# if defined(__PPC64__)
|
||||||
|
# define ARCHITECTURE_ID "PPC64"
|
||||||
|
|
||||||
|
# elif defined(__ppc__)
|
||||||
|
# define ARCHITECTURE_ID "PPC"
|
||||||
|
|
||||||
|
# elif defined(__ARM__)
|
||||||
|
# define ARCHITECTURE_ID "ARM"
|
||||||
|
|
||||||
|
# elif defined(__x86_64__)
|
||||||
|
# define ARCHITECTURE_ID "x64"
|
||||||
|
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define ARCHITECTURE_ID "X86"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__TI_COMPILER_VERSION__)
|
||||||
|
# if defined(__TI_ARM__)
|
||||||
|
# define ARCHITECTURE_ID "ARM"
|
||||||
|
|
||||||
|
# elif defined(__MSP430__)
|
||||||
|
# define ARCHITECTURE_ID "MSP430"
|
||||||
|
|
||||||
|
# elif defined(__TMS320C28XX__)
|
||||||
|
# define ARCHITECTURE_ID "TMS320C28x"
|
||||||
|
|
||||||
|
# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
|
||||||
|
# define ARCHITECTURE_ID "TMS320C6x"
|
||||||
|
|
||||||
|
# else /* unknown architecture */
|
||||||
|
# define ARCHITECTURE_ID ""
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define ARCHITECTURE_ID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Convert integer to decimal digit literals. */
|
||||||
|
#define DEC(n) \
|
||||||
|
('0' + (((n) / 10000000)%10)), \
|
||||||
|
('0' + (((n) / 1000000)%10)), \
|
||||||
|
('0' + (((n) / 100000)%10)), \
|
||||||
|
('0' + (((n) / 10000)%10)), \
|
||||||
|
('0' + (((n) / 1000)%10)), \
|
||||||
|
('0' + (((n) / 100)%10)), \
|
||||||
|
('0' + (((n) / 10)%10)), \
|
||||||
|
('0' + ((n) % 10))
|
||||||
|
|
||||||
|
/* Convert integer to hex digit literals. */
|
||||||
|
#define HEX(n) \
|
||||||
|
('0' + ((n)>>28 & 0xF)), \
|
||||||
|
('0' + ((n)>>24 & 0xF)), \
|
||||||
|
('0' + ((n)>>20 & 0xF)), \
|
||||||
|
('0' + ((n)>>16 & 0xF)), \
|
||||||
|
('0' + ((n)>>12 & 0xF)), \
|
||||||
|
('0' + ((n)>>8 & 0xF)), \
|
||||||
|
('0' + ((n)>>4 & 0xF)), \
|
||||||
|
('0' + ((n) & 0xF))
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the version number. */
|
||||||
|
#ifdef COMPILER_VERSION
|
||||||
|
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the version number components. */
|
||||||
|
#elif defined(COMPILER_VERSION_MAJOR)
|
||||||
|
char const info_version[] = {
|
||||||
|
'I', 'N', 'F', 'O', ':',
|
||||||
|
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
|
||||||
|
COMPILER_VERSION_MAJOR,
|
||||||
|
# ifdef COMPILER_VERSION_MINOR
|
||||||
|
'.', COMPILER_VERSION_MINOR,
|
||||||
|
# ifdef COMPILER_VERSION_PATCH
|
||||||
|
'.', COMPILER_VERSION_PATCH,
|
||||||
|
# ifdef COMPILER_VERSION_TWEAK
|
||||||
|
'.', COMPILER_VERSION_TWEAK,
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
']','\0'};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the internal version number. */
|
||||||
|
#ifdef COMPILER_VERSION_INTERNAL
|
||||||
|
char const info_version_internal[] = {
|
||||||
|
'I', 'N', 'F', 'O', ':',
|
||||||
|
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
|
||||||
|
'i','n','t','e','r','n','a','l','[',
|
||||||
|
COMPILER_VERSION_INTERNAL,']','\0'};
|
||||||
|
#elif defined(COMPILER_VERSION_INTERNAL_STR)
|
||||||
|
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct a string literal encoding the version number components. */
|
||||||
|
#ifdef SIMULATE_VERSION_MAJOR
|
||||||
|
char const info_simulate_version[] = {
|
||||||
|
'I', 'N', 'F', 'O', ':',
|
||||||
|
's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
|
||||||
|
SIMULATE_VERSION_MAJOR,
|
||||||
|
# ifdef SIMULATE_VERSION_MINOR
|
||||||
|
'.', SIMULATE_VERSION_MINOR,
|
||||||
|
# ifdef SIMULATE_VERSION_PATCH
|
||||||
|
'.', SIMULATE_VERSION_PATCH,
|
||||||
|
# ifdef SIMULATE_VERSION_TWEAK
|
||||||
|
'.', SIMULATE_VERSION_TWEAK,
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
']','\0'};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Construct the string literal in pieces to prevent the source from
|
||||||
|
getting matched. Store it in a pointer rather than an array
|
||||||
|
because some compilers will just produce instructions to fill the
|
||||||
|
array rather than assigning a pointer to a static array. */
|
||||||
|
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
|
||||||
|
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L
|
||||||
|
# if defined(__INTEL_CXX11_MODE__)
|
||||||
|
# if defined(__cpp_aggregate_nsdmi)
|
||||||
|
# define CXX_STD 201402L
|
||||||
|
# else
|
||||||
|
# define CXX_STD 201103L
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define CXX_STD 199711L
|
||||||
|
# endif
|
||||||
|
#elif defined(_MSC_VER) && defined(_MSVC_LANG)
|
||||||
|
# define CXX_STD _MSVC_LANG
|
||||||
|
#else
|
||||||
|
# define CXX_STD __cplusplus
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* info_language_standard_default = "INFO" ":" "standard_default["
|
||||||
|
#if CXX_STD > 202002L
|
||||||
|
"23"
|
||||||
|
#elif CXX_STD > 201703L
|
||||||
|
"20"
|
||||||
|
#elif CXX_STD >= 201703L
|
||||||
|
"17"
|
||||||
|
#elif CXX_STD >= 201402L
|
||||||
|
"14"
|
||||||
|
#elif CXX_STD >= 201103L
|
||||||
|
"11"
|
||||||
|
#else
|
||||||
|
"98"
|
||||||
|
#endif
|
||||||
|
"]";
|
||||||
|
|
||||||
|
const char* info_language_extensions_default = "INFO" ":" "extensions_default["
|
||||||
|
/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */
|
||||||
|
#if (defined(__clang__) || defined(__GNUC__) || \
|
||||||
|
defined(__TI_COMPILER_VERSION__)) && \
|
||||||
|
!defined(__STRICT_ANSI__) && !defined(_MSC_VER)
|
||||||
|
"ON"
|
||||||
|
#else
|
||||||
|
"OFF"
|
||||||
|
#endif
|
||||||
|
"]";
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int require = 0;
|
||||||
|
require += info_compiler[argc];
|
||||||
|
require += info_platform[argc];
|
||||||
|
#ifdef COMPILER_VERSION_MAJOR
|
||||||
|
require += info_version[argc];
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILER_VERSION_INTERNAL
|
||||||
|
require += info_version_internal[argc];
|
||||||
|
#endif
|
||||||
|
#ifdef SIMULATE_ID
|
||||||
|
require += info_simulate[argc];
|
||||||
|
#endif
|
||||||
|
#ifdef SIMULATE_VERSION_MAJOR
|
||||||
|
require += info_simulate_version[argc];
|
||||||
|
#endif
|
||||||
|
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
|
||||||
|
require += info_cray[argc];
|
||||||
|
#endif
|
||||||
|
require += info_language_standard_default[argc];
|
||||||
|
require += info_language_extensions_default[argc];
|
||||||
|
(void)argv;
|
||||||
|
return require;
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,3 @@
|
|||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/appmodules.dir
|
||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/edit_cache.dir
|
||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/rebuild_cache.dir
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# CMAKE generated file: DO NOT EDIT!
|
||||||
|
# Generated by CMake Version 3.22
|
||||||
|
cmake_policy(SET CMP0009 NEW)
|
||||||
|
|
||||||
|
# input_SRC at /home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake:55 (file)
|
||||||
|
file(GLOB NEW_GLOB LIST_DIRECTORIES true "/home/echo/dev/prototype/apps/mobile/android/app/build/generated/autolinking/src/main/jni/*.cpp")
|
||||||
|
set(OLD_GLOB
|
||||||
|
)
|
||||||
|
if(NOT "${NEW_GLOB}" STREQUAL "${OLD_GLOB}")
|
||||||
|
message("-- GLOB mismatch!")
|
||||||
|
file(TOUCH_NOCREATE "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/cmake.verify_globs")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# override_cpp_SRC at /home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake:50 (file)
|
||||||
|
# input_SRC at /home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake:55 (file)
|
||||||
|
file(GLOB NEW_GLOB LIST_DIRECTORIES true "/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup/*.cpp")
|
||||||
|
set(OLD_GLOB
|
||||||
|
"/home/echo/dev/prototype/apps/mobile/node_modules/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp"
|
||||||
|
)
|
||||||
|
if(NOT "${NEW_GLOB}" STREQUAL "${OLD_GLOB}")
|
||||||
|
message("-- GLOB mismatch!")
|
||||||
|
file(TOUCH_NOCREATE "/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/cmake.verify_globs")
|
||||||
|
endif()
|
||||||
BIN
Binary file not shown.
+4
@@ -0,0 +1,4 @@
|
|||||||
|
# ninja log v5
|
||||||
|
0 17 1764608951217248929 CMakeFiles/foo.dir/foo.cpp.o cf03112569101c0d
|
||||||
|
0 17 1764608951217248929 CMakeFiles/boo.dir/main.cpp.o a40c4ac8f9333fbb
|
||||||
|
17 47 1764608951246597989 libfoo.a 46ab43a90edc58a3
|
||||||
+281
@@ -0,0 +1,281 @@
|
|||||||
|
# This is the CMakeCache file.
|
||||||
|
# For build in directory: /home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin
|
||||||
|
# It was generated by CMake: /home/echo/Android/Sdk/cmake/3.22.1/bin/cmake
|
||||||
|
# You can edit this file to change values found and used by cmake.
|
||||||
|
# If you do not want to change any of the values, simply exit the editor.
|
||||||
|
# If you do want to change a value, simply edit, save, and exit the editor.
|
||||||
|
# The syntax for the file is as follows:
|
||||||
|
# KEY:TYPE=VALUE
|
||||||
|
# KEY is the name of a variable in the cache.
|
||||||
|
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
|
||||||
|
# VALUE is the current value for the KEY.
|
||||||
|
|
||||||
|
########################
|
||||||
|
# EXTERNAL cache entries
|
||||||
|
########################
|
||||||
|
|
||||||
|
//Archiver
|
||||||
|
CMAKE_AR:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
|
||||||
|
|
||||||
|
//Flags used by the compiler during all build types.
|
||||||
|
CMAKE_ASM_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during debug builds.
|
||||||
|
CMAKE_ASM_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during release builds.
|
||||||
|
CMAKE_ASM_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Choose the type of build, options are: None Debug Release RelWithDebInfo
|
||||||
|
// MinSizeRel ...
|
||||||
|
CMAKE_BUILD_TYPE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during all build types.
|
||||||
|
CMAKE_CXX_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during debug builds.
|
||||||
|
CMAKE_CXX_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the CXX compiler during MINSIZEREL builds.
|
||||||
|
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
|
||||||
|
|
||||||
|
//Flags used by the compiler during release builds.
|
||||||
|
CMAKE_CXX_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the CXX compiler during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
|
||||||
|
|
||||||
|
//Libraries linked by default with all C++ applications.
|
||||||
|
CMAKE_CXX_STANDARD_LIBRARIES:STRING=-latomic -lm
|
||||||
|
|
||||||
|
//Flags used by the compiler during all build types.
|
||||||
|
CMAKE_C_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during debug builds.
|
||||||
|
CMAKE_C_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the compiler during release builds.
|
||||||
|
CMAKE_C_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during DEBUG builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during MINSIZEREL builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during RELEASE builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//Enable/Disable output of compile commands during generation.
|
||||||
|
CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=
|
||||||
|
|
||||||
|
//Install path prefix, prepended onto install directories.
|
||||||
|
CMAKE_INSTALL_PREFIX:PATH=/usr/local
|
||||||
|
|
||||||
|
//No help, variable specified on the command line.
|
||||||
|
CMAKE_INTERPROCEDURAL_OPTIMIZATION:UNINITIALIZED=ON
|
||||||
|
|
||||||
|
//make program
|
||||||
|
CMAKE_MAKE_PROGRAM:FILEPATH=/home/echo/Android/Sdk/cmake/3.22.1/bin/ninja
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// DEBUG builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// MINSIZEREL builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// RELEASE builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of modules during
|
||||||
|
// RELWITHDEBINFO builds.
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
CMAKE_PROJECT_DESCRIPTION:STATIC=
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
CMAKE_PROJECT_NAME:STATIC=lto-test
|
||||||
|
|
||||||
|
//Ranlib
|
||||||
|
CMAKE_RANLIB:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of dll's.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during DEBUG builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during MINSIZEREL builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during RELEASE builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of shared libraries
|
||||||
|
// during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//If set, runtime paths are not added when installing shared libraries,
|
||||||
|
// but are added when building.
|
||||||
|
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
|
||||||
|
|
||||||
|
//If set, runtime paths are not added when using shared libraries.
|
||||||
|
CMAKE_SKIP_RPATH:BOOL=NO
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during all build types.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during DEBUG builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during MINSIZEREL builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during RELEASE builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
|
||||||
|
|
||||||
|
//Flags used by the linker during the creation of static libraries
|
||||||
|
// during RELWITHDEBINFO builds.
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||||
|
|
||||||
|
//Strip
|
||||||
|
CMAKE_STRIP:FILEPATH=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip
|
||||||
|
|
||||||
|
//If this value is on, makefiles will be generated without the
|
||||||
|
// .SILENT directive, and all commands will be echoed to the console
|
||||||
|
// during the make. This is useful for debugging only. With Visual
|
||||||
|
// Studio IDE projects all commands are done without /nologo.
|
||||||
|
CMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
lto-test_BINARY_DIR:STATIC=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
lto-test_IS_TOP_LEVEL:STATIC=ON
|
||||||
|
|
||||||
|
//Value Computed by CMake
|
||||||
|
lto-test_SOURCE_DIR:STATIC=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/src
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
# INTERNAL cache entries
|
||||||
|
########################
|
||||||
|
|
||||||
|
//This is the directory where this CMakeCache.txt was created
|
||||||
|
CMAKE_CACHEFILE_DIR:INTERNAL=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin
|
||||||
|
//Major version of cmake used to create the current loaded cache
|
||||||
|
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
|
||||||
|
//Minor version of cmake used to create the current loaded cache
|
||||||
|
CMAKE_CACHE_MINOR_VERSION:INTERNAL=22
|
||||||
|
//Patch version of cmake used to create the current loaded cache
|
||||||
|
CMAKE_CACHE_PATCH_VERSION:INTERNAL=1
|
||||||
|
//Path to CMake executable.
|
||||||
|
CMAKE_COMMAND:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/bin/cmake
|
||||||
|
//Path to cpack program executable.
|
||||||
|
CMAKE_CPACK_COMMAND:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/bin/cpack
|
||||||
|
//Path to ctest program executable.
|
||||||
|
CMAKE_CTEST_COMMAND:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/bin/ctest
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS
|
||||||
|
CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
|
||||||
|
CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
|
||||||
|
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_CXX_STANDARD_LIBRARIES
|
||||||
|
CMAKE_CXX_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
|
||||||
|
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
|
||||||
|
CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
|
||||||
|
//Name of external makefile project generator.
|
||||||
|
CMAKE_EXTRA_GENERATOR:INTERNAL=
|
||||||
|
//Name of generator.
|
||||||
|
CMAKE_GENERATOR:INTERNAL=Ninja
|
||||||
|
//Generator instance identifier.
|
||||||
|
CMAKE_GENERATOR_INSTANCE:INTERNAL=
|
||||||
|
//Name of generator platform.
|
||||||
|
CMAKE_GENERATOR_PLATFORM:INTERNAL=
|
||||||
|
//Name of generator toolset.
|
||||||
|
CMAKE_GENERATOR_TOOLSET:INTERNAL=
|
||||||
|
//Source directory with the top level CMakeLists.txt file for this
|
||||||
|
// project
|
||||||
|
CMAKE_HOME_DIRECTORY:INTERNAL=/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/src
|
||||||
|
//Install .so files without execute permission.
|
||||||
|
CMAKE_INSTALL_SO_NO_EXE:INTERNAL=0
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//number of local generators
|
||||||
|
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
|
||||||
|
//Path to CMake installation.
|
||||||
|
CMAKE_ROOT:INTERNAL=/home/echo/Android/Sdk/cmake/3.22.1/share/cmake-3.22
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
|
||||||
|
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_SKIP_RPATH
|
||||||
|
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||||
|
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
|
||||||
|
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||||
|
CMAKE_SUPPRESS_DEVELOPER_WARNINGS:INTERNAL=FALSE
|
||||||
|
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
|
||||||
|
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
|
||||||
|
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin/CMakeFiles/foo.dir
|
||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin/CMakeFiles/boo.dir
|
||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin/CMakeFiles/edit_cache.dir
|
||||||
|
/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin/CMakeFiles/rebuild_cache.dir
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
# This file is generated by cmake for dependency checking of the CMakeCache.txt file
|
||||||
BIN
Binary file not shown.
+83
@@ -0,0 +1,83 @@
|
|||||||
|
# CMAKE generated file: DO NOT EDIT!
|
||||||
|
# Generated by "Ninja" Generator, CMake Version 3.22
|
||||||
|
|
||||||
|
# This file contains all the rules used to get the outputs files
|
||||||
|
# built from the input files.
|
||||||
|
# It is included in the main 'build.ninja'.
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Project: lto-test
|
||||||
|
# Configurations:
|
||||||
|
# =============================================================================
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for compiling CXX files.
|
||||||
|
|
||||||
|
rule CXX_COMPILER__foo_
|
||||||
|
depfile = $DEP_FILE
|
||||||
|
deps = gcc
|
||||||
|
command = /home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=armv7-none-linux-androideabi21 --sysroot=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot $DEFINES $INCLUDES $FLAGS -MD -MT $out -MF $DEP_FILE -o $out -c $in
|
||||||
|
description = Building CXX object $out
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for linking CXX static library.
|
||||||
|
|
||||||
|
rule CXX_STATIC_LIBRARY_LINKER__foo_
|
||||||
|
command = $PRE_LINK && /home/echo/Android/Sdk/cmake/3.22.1/bin/cmake -E rm -f $TARGET_FILE && "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" cr $TARGET_FILE $LINK_FLAGS $in && "/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib" $TARGET_FILE && $POST_BUILD
|
||||||
|
description = Linking CXX static library $TARGET_FILE
|
||||||
|
restat = $RESTAT
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for compiling CXX files.
|
||||||
|
|
||||||
|
rule CXX_COMPILER__boo_
|
||||||
|
depfile = $DEP_FILE
|
||||||
|
deps = gcc
|
||||||
|
command = /home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=armv7-none-linux-androideabi21 --sysroot=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot $DEFINES $INCLUDES $FLAGS -MD -MT $out -MF $DEP_FILE -o $out -c $in
|
||||||
|
description = Building CXX object $out
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for linking CXX executable.
|
||||||
|
|
||||||
|
rule CXX_EXECUTABLE_LINKER__boo_
|
||||||
|
command = $PRE_LINK && /home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=armv7-none-linux-androideabi21 --sysroot=/home/echo/Android/Sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot $FLAGS $LINK_FLAGS $in -o $TARGET_FILE $LINK_PATH $LINK_LIBRARIES && $POST_BUILD
|
||||||
|
description = Linking CXX executable $TARGET_FILE
|
||||||
|
restat = $RESTAT
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for running custom commands.
|
||||||
|
|
||||||
|
rule CUSTOM_COMMAND
|
||||||
|
command = $COMMAND
|
||||||
|
description = $DESC
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for re-running cmake.
|
||||||
|
|
||||||
|
rule RERUN_CMAKE
|
||||||
|
command = /home/echo/Android/Sdk/cmake/3.22.1/bin/cmake --regenerate-during-build -S/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/src -B/home/echo/dev/prototype/apps/mobile/android/app/.cxx/Debug/2z472e3c/x86/CMakeFiles/_CMakeLTOTest-CXX/bin
|
||||||
|
description = Re-running CMake...
|
||||||
|
generator = 1
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for cleaning all built files.
|
||||||
|
|
||||||
|
rule CLEAN
|
||||||
|
command = /home/echo/Android/Sdk/cmake/3.22.1/bin/ninja $FILE_ARG -t clean $TARGETS
|
||||||
|
description = Cleaning all built files...
|
||||||
|
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Rule for printing all primary targets available.
|
||||||
|
|
||||||
|
rule HELP
|
||||||
|
command = /home/echo/Android/Sdk/cmake/3.22.1/bin/ninja -t targets
|
||||||
|
description = All primary targets available:
|
||||||
|
|
||||||
Loaded 100 of 266 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user