import { apiRequest } from '../../lib/api'; export type PageParams = { page?: number; limit?: number; keyword?: string; [key: string]: string | number | undefined; }; export type PagedResponse = { items: T[]; total: number; page: number; limit: number; }; function pageQuery(params?: PageParams) { const searchParams = new URLSearchParams(); Object.entries(params ?? {}).forEach(([key, value]) => { if (value !== undefined && value !== '') searchParams.set(key, String(value)); }); const query = searchParams.toString(); return query ? `?${query}` : ''; } export type AdminSession = { id?: string; revokedAt?: string | null; }; export type AdminSshKey = { id: string; label?: string | null; fingerprint?: string | null; }; export type AdminAccount = { id: string; no?: number; email: string; name: string; avatarUrl?: string | null; role: 'OWNER' | 'ADMIN' | 'OPERATOR' | 'VIEWER' | string; isActive: boolean; lastLoginAt?: string | null; sessions?: AdminSession[]; sshKeys?: AdminSshKey[]; appPermissions?: string[]; }; export type AdminRoleOption = { id: string; code: string; name: string; description?: string | null; sortOrder: number; isActive: boolean; }; export type UserSession = { id: string; no?: number; userId: string; sessionId?: string | null; user: string; email?: string; avatarUrl?: string | null; role: string; session: string; expiresAt?: string | null; lastSeen?: string | null; state: string; primaryAffiliation?: { id: string; organizationId: string; organizationName: string; organizationType: string; department?: string | null; position?: string | null; } | null; }; export type OrganizationType = 'COMPANY' | 'SCHOOL' | 'GOVERNMENT' | 'LAB' | 'OTHER' | string; export type Organization = { id: string; no?: number; name: string; type: OrganizationType; domain?: string | null; defaultLicenseCode?: string | null; defaultLicenseName?: string | null; createdAt: string; }; export type LauncherNotice = { id: string; no?: number; appKey: string; title: string; body: string; linkUrl?: string | null; isActive: boolean; startsAt?: string | null; endsAt?: string | null; priority: number; status?: string; createdByName?: string | null; createdByEmail?: string | null; createdByAvatarUrl?: string | null; createdAt: string; updatedAt?: string; }; export type LauncherTerm = { id: string; no?: number; key: string; body: string; isRequired: boolean; createdById?: string | null; createdByName?: string | null; createdByEmail?: string | null; createdByAvatarUrl?: string | null; createdAt: string; updatedAt?: string; }; export async function loadAdminsPage(params?: PageParams & { role?: string; state?: string }): Promise> { type RawAdminAccount = Omit & { appPermissions?: Array; }; const response = await apiRequest(`/admins${pageQuery(params)}`); const admins = Array.isArray(response) ? response : response.admins ?? []; const items = admins.map((admin) => ({ ...admin, appPermissions: (admin.appPermissions ?? []).map((permission) => ( typeof permission === 'string' ? permission : permission.appId )) })); if (Array.isArray(response)) return { items, total: items.length, page: params?.page ?? 1, limit: params?.limit ?? items.length }; return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length }; } export async function loadAdmins() { return (await loadAdminsPage({ limit: 1000 })).items; } export function loadAdminRoles() { return apiRequest('/admins/roles'); } export function createAdmin(payload: { email: string; name: string; role: string; temporaryPassword?: string; }) { return apiRequest('/admins', { method: 'POST', body: JSON.stringify(payload) }); } export function updateAdminStatus(adminId: string, isActive: boolean) { return apiRequest(`/admins/${adminId}/status`, { method: 'PATCH', body: JSON.stringify({ isActive }) }); } export function updateAdminRole(adminId: string, role: string) { return apiRequest(`/admins/${adminId}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); } export function resetAdminPassword(adminId: string, temporaryPassword: string) { return apiRequest(`/admins/${adminId}/password`, { method: 'PATCH', body: JSON.stringify({ temporaryPassword }) }); } export function createAdminSshKey( adminId: string, payload: { label?: string; publicKey: string } ) { return apiRequest(`/admins/${adminId}/ssh-keys`, { method: 'POST', body: JSON.stringify(payload) }); } export function deleteAdminSshKey(adminId: string, keyId: string) { return apiRequest(`/admins/${adminId}/ssh-keys/${keyId}`, { method: 'DELETE' }); } export async function loadAdminAppPermissions(adminId: string) { const response = await apiRequest<{ appIds?: string[] }>(`/admins/${adminId}/app-permissions`); return response.appIds ?? []; } export function updateAdminAppPermissions(adminId: string, appIds: string[]) { return apiRequest<{ appIds?: string[] }>(`/admins/${adminId}/app-permissions`, { method: 'PUT', body: JSON.stringify({ appIds }) }); } export async function loadUserSessionsPage(params?: PageParams & { state?: string }): Promise> { const response = await apiRequest<{ sessions?: UserSession[]; total?: number; page?: number; limit?: number }>(`/users/sessions${pageQuery(params)}`); const items = (response.sessions ?? []).map((session) => ({ ...session, session: session.sessionId ? session.session : '-', state: session.state })); return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length }; } export async function loadUserSessions() { return (await loadUserSessionsPage({ limit: 1000 })).items; } export function lockUser(userId: string) { return apiRequest(`/users/${userId}/lock`, { method: 'PATCH' }); } export function unlockUser(userId: string) { return apiRequest(`/users/${userId}/unlock`, { method: 'PATCH' }); } export function terminateUserSession(sessionId: string) { return apiRequest(`/users/sessions/${sessionId}`, { method: 'DELETE' }); } export function createManagedUser(payload: { email: string; password: string; name: string; organizationId?: string | null; department?: string | null; position?: string | null; licenseCode?: 'FREE' | 'EDU' | 'PRO'; }) { return apiRequest<{ user: { id: string; email: string; name?: string | null } }>('/users', { method: 'POST', body: JSON.stringify(payload) }); } export async function loadOrganizationsPage(params?: PageParams & { type?: string }): Promise> { const response = await apiRequest<{ organizations?: Organization[]; total?: number; page?: number; limit?: number }>(`/organizations${pageQuery(params)}`); const items = response.organizations ?? []; return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length }; } export async function loadOrganizations() { return (await loadOrganizationsPage({ limit: 1000 })).items; } export function createOrganization(payload: { name: string; type: OrganizationType; domain?: string | null }) { return apiRequest<{ organization: Organization }>('/organizations', { method: 'POST', body: JSON.stringify(payload) }); } export function updateOrganization(organizationId: string, payload: { name?: string; type?: OrganizationType; domain?: string | null }) { return apiRequest<{ organization: Organization }>(`/organizations/${organizationId}`, { method: 'PATCH', body: JSON.stringify(payload) }); } export function deleteOrganization(organizationId: string) { return apiRequest<{ ok: boolean }>(`/organizations/${organizationId}`, { method: 'DELETE' }); } export function updateOrganizationLicense(organizationId: string, licenseCode: string | null) { return apiRequest<{ organization: Organization; updatedUserCount: number }>(`/organizations/${organizationId}/license`, { method: 'PATCH', body: JSON.stringify({ licenseCode }) }); } export async function loadLauncherNoticesPage(params?: PageParams & { appKey?: string }): Promise> { const response = await apiRequest<{ notices?: LauncherNotice[]; total?: number; page?: number; limit?: number }>(`/notices${pageQuery(params)}`); const items = response.notices ?? []; return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length }; } export async function loadLauncherNotices() { return (await loadLauncherNoticesPage({ limit: 1000 })).items; } export function createLauncherNotice(payload: { appKey: string; title: string; body: string; linkUrl?: string; isActive?: boolean; startsAt?: string; endsAt?: string; priority?: number; }) { return apiRequest<{ notice: LauncherNotice }>('/notices', { method: 'POST', body: JSON.stringify(payload) }); } export function updateLauncherNotice( noticeId: string, payload: Partial<{ appKey: string; title: string; body: string; linkUrl: string; isActive: boolean; startsAt: string; endsAt: string; priority: number; }> ) { return apiRequest<{ notice: LauncherNotice }>(`/notices/${noticeId}`, { method: 'PATCH', body: JSON.stringify(payload) }); } export function deleteLauncherNotice(noticeId: string) { return apiRequest<{ ok: boolean }>(`/notices/${noticeId}`, { method: 'DELETE' }); } export async function loadTermsPage(params?: PageParams & { key?: string }): Promise> { const response = await apiRequest<{ terms?: LauncherTerm[]; total?: number; page?: number; limit?: number }>(`/terms${pageQuery(params)}`); const items = response.terms ?? []; return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length }; } export function createTerm(payload: { key: string; body: string; isRequired?: boolean; }) { return apiRequest<{ term: LauncherTerm }>('/terms', { method: 'POST', body: JSON.stringify(payload) }); } export function updateTerm( termId: string, payload: Partial<{ key: string; body: string; isRequired: boolean; }> ) { return apiRequest<{ term: LauncherTerm }>(`/terms/${termId}`, { method: 'PATCH', body: JSON.stringify(payload) }); } export function deleteTerm(termId: string) { return apiRequest<{ ok: boolean }>(`/terms/${termId}`, { method: 'DELETE' }); } export type LicensePlan = { id: string; code: string; name: string; description?: string | null; defaultDurationDays?: number | null; isActive: boolean; assignedCount: number; activeUserCount: number; expiringSoonCount: number; createdAt?: string; updatedAt?: string; }; export type AuthUserLicense = { id: string; userId: string; licenseId: string; startsAt: string; expiresAt?: string | null; assignedById?: string | null; license: { id: string; code: string; name: string; description?: string | null; }; status: string; }; export type AuthLicenseUser = { id: string; email: string; name: string; role: string; isActive: boolean; currentLicense?: AuthUserLicense | null; licenses: AuthUserLicense[]; }; export async function loadLicensePlans() { const response = await apiRequest<{ plans?: LicensePlan[] }>('/licenses/plans'); return response.plans ?? []; } export function updateLicensePlan(licenseCode: string, payload: { name?: string; description?: string | null; defaultDurationDays?: number | null; isActive?: boolean; permissions?: Array<{ appKey: string; canLaunch: boolean }>; }) { return apiRequest<{ plan: LicensePlan; updatedUserCount?: number }>(`/licenses/plans/${encodeURIComponent(licenseCode)}`, { method: 'PATCH', body: JSON.stringify(payload) }); } export async function loadLicenseUsers(params?: { keyword?: string; licenseCode?: string }) { const searchParams = new URLSearchParams(); if (params?.keyword) searchParams.set('keyword', params.keyword); if (params?.licenseCode) searchParams.set('licenseCode', params.licenseCode); const suffix = searchParams.toString() ? `?${searchParams.toString()}` : ''; const response = await apiRequest<{ users?: AuthLicenseUser[] }>(`/licenses/users${suffix}`); return response.users ?? []; } export async function loadLicenseAssignments(params?: PageParams & { licenseCode?: string; status?: string }): Promise> { const response = await apiRequest<{ assignments?: LicenseAssignment[]; total?: number; page?: number; limit?: number }>(`/licenses/assignments${pageQuery(params)}`); const items = response.assignments ?? []; return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length }; } export type LicenseAssignment = { id: string; no?: number; userId: string; user: string; name: string; role: string; code: string; licenseName: string; startsAt: string; expiresAt?: string | null; assignedBy?: string | null; status: string; }; export function assignUserLicense(userId: string, payload: { licenseCode: string; startsAt?: string; expiresAt?: string; }) { return apiRequest<{ userLicense: AuthUserLicense }>(`/licenses/users/${userId}`, { method: 'POST', body: JSON.stringify(payload) }); } export function updateUserLicense(userLicenseId: string, payload: { licenseCode: string; startsAt?: string; expiresAt?: string; }) { return apiRequest<{ userLicense: AuthUserLicense }>(`/licenses/user-licenses/${userLicenseId}`, { method: 'PATCH', body: JSON.stringify(payload) }); } export function revokeUserLicense(userLicenseId: string) { return apiRequest<{ ok: boolean }>(`/licenses/user-licenses/${userLicenseId}`, { method: 'DELETE' }); } export type LauncherUserAppPermission = { appId: string; appKey: string; displayName: string; description?: string | null; sortOrder: number; isEnabled: boolean; permissionId?: string | null; canView: boolean; canLaunch: boolean; assignedAt?: string | null; }; export type LicenseAppPermission = { appId: string; appKey: string; displayName: string; description?: string | null; sortOrder: number; isEnabled: boolean; policyId?: string | null; canView: boolean; canLaunch: boolean; }; export async function loadLicenseAppPermissions(licenseCode: string) { const response = await apiRequest<{ permissions?: LicenseAppPermission[] }>(`/licenses/plans/${encodeURIComponent(licenseCode)}/app-permissions`); return response.permissions ?? []; } export function updateLicenseAppPermissions(licenseCode: string, permissions: Array<{ appKey: string; canLaunch: boolean; }>) { return apiRequest<{ permissions?: LicenseAppPermission[]; updatedUserCount?: number }>(`/licenses/plans/${encodeURIComponent(licenseCode)}/app-permissions`, { method: 'PUT', body: JSON.stringify({ permissions }) }); } export async function loadLauncherUserAppPermissions(userId: string) { const response = await apiRequest<{ permissions?: LauncherUserAppPermission[] }>(`/launcher/users/${userId}/app-permissions`); return response.permissions ?? []; } export function updateLauncherUserAppPermissions(userId: string, permissions: Array<{ appKey: string; canView: boolean; canLaunch: boolean; }>) { return apiRequest<{ permissions?: LauncherUserAppPermission[] }>(`/launcher/users/${userId}/app-permissions`, { method: 'PUT', body: JSON.stringify({ permissions }) }); }