academe-kit
v0.3.7
Published
Official React SDK for Academe ecosystem - Authentication, protected routes, API services, and UI components for educational management applications
Maintainers
Readme
Academe Kit
Official React SDK for the Academe ecosystem. Provides authentication, protected routes, API services, and UI components for building educational management applications.
Table of Contents
- Features
- Installation
- Quick Start
- Authentication
- Protected Components
- API Services
- Roles
- UI Components
- Types
- Development
- License
Features
- Authentication: Keycloak-based authentication with automatic token management
- Protected Routes: Role-based access control for routes and components
- API Client: Type-safe API client with OpenAPI-generated types
- Services: Pre-built services for Users, Institutions, Classrooms, and more
- UI Components: Reusable React components styled with Tailwind CSS
- TypeScript: Full TypeScript support with comprehensive type definitions
Installation
npm install academe-kitPeer Dependencies:
npm install react react-domQuick Start
import { AcademeAuthProvider, ProtectedApp, useAcademeAuth } from 'academe-kit';
import 'academe-kit/dist/index.css';
function App() {
return (
<AcademeAuthProvider
realm="your-realm"
hubUrl="https://hub.academe.com.br"
clientId="your-client-id"
keycloakUrl="https://auth.academe.com.br"
apiBaseUrl="https://api.academe.com.br"
>
<ProtectedApp>
<MainApp />
</ProtectedApp>
</AcademeAuthProvider>
);
}
function MainApp() {
const { user, services } = useAcademeAuth();
return (
<div>
<h1>Welcome, {user?.name}</h1>
</div>
);
}Authentication
AcademeAuthProvider
The main provider that wraps your application and handles authentication with Keycloak.
import { AcademeAuthProvider } from 'academe-kit';
<AcademeAuthProvider
realm="your-realm" // Keycloak realm name
hubUrl="https://hub.url" // Academe Hub URL
clientId="your-client-id" // Keycloak client ID
keycloakUrl="https://kc.url" // Keycloak server URL
apiBaseUrl="https://api.url" // Optional: API base URL (default: https://stg-api.academe.com.br)
>
{children}
</AcademeAuthProvider>useAcademeAuth Hook
Access authentication state and methods from any component within the provider.
import { useAcademeAuth } from 'academe-kit';
function MyComponent() {
const {
// State
isInitialized, // boolean - Provider initialization status
user, // AcademeUser | null - Current user data
apiClient, // AcademeApiClient | null - Type-safe API client
services, // AcademeServices | null - All available services
// Methods
isAuthenticated, // () => boolean - Check authentication status
signOut, // () => void - Sign out and clear session
goToLogin, // (options?) => void - Redirect to login
refreshUserData, // () => Promise<void> - Refresh user data from API
// Role checks
hasRealmRole, // (role: string) => boolean
hasClientRole, // (role: string, resource?: string) => boolean
hasSchool, // (schoolId: string) => boolean
} = useAcademeAuth();
return (
<div>
{isAuthenticated() ? (
<p>Logged in as {user?.name}</p>
) : (
<button onClick={() => goToLogin()}>Login</button>
)}
</div>
);
}User Object
interface AcademeUser {
id: string;
name: string;
email: string;
document?: string;
institutionRegistrations?: InstitutionRegistration[];
keycloakUser?: {
name: string;
lastName: string;
email: string;
};
// ... other fields from API
}Protected Components
ProtectedApp
Wraps your entire application to ensure authentication before rendering. Shows a loading spinner during initialization and redirects unauthenticated users to login.
import { ProtectedApp } from 'academe-kit';
<ProtectedApp
requiredRealmRoles={['school_admin']} // Optional: Required realm roles
requiredClientRoles={['manage-users']} // Optional: Required client roles
>
<YourApp />
</ProtectedApp>ProtectedComponent
Conditionally renders children based on user roles. Returns empty fragment if user lacks required permissions.
import { ProtectedComponent } from 'academe-kit';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
{/* Only visible to admins */}
<ProtectedComponent requiredRealmRoles={['admin_academe']}>
<AdminPanel />
</ProtectedComponent>
{/* Only visible to users with specific client role */}
<ProtectedComponent requiredClientRoles={['manage-reports']}>
<ReportsSection />
</ProtectedComponent>
</div>
);
}ProtectedRouter
Route-level protection that shows an unauthorized message instead of hiding content.
import { ProtectedRouter } from 'academe-kit';
function AdminPage() {
return (
<ProtectedRouter
requiredClientRoles={['admin-access']}
unauthorizedMessage="You don't have permission to access this page."
>
<AdminDashboard />
</ProtectedRouter>
);
}API Services
All services are available through the useAcademeAuth hook via services object.
const { services } = useAcademeAuth();
// Use any service
const users = await services.user.getUsers();
const institutions = await services.institution.getAll();UserService
services.user.getMe() // Get current user
services.user.getUsers(params?) // List users with filters
services.user.getUserById(id) // Get user by ID
services.user.createUser(body) // Create new user
services.user.updateUser(id, body) // Update user
services.user.deleteUser(id) // Delete user
services.user.getUserGroups(id) // Get user's groups
services.user.getUserCertificates(id) // Get user's certificates
services.user.getUserInstitutions(id) // Get user's institutions
services.user.syncUser(id) // Sync with KeycloakInstitutionService
services.institution.getAll() // List all institutions
services.institution.getById(id) // Get institution by ID
// Groups
services.institution.getGroups(institutionId)
services.institution.addGroup(institutionId, data)
services.institution.updateGroup(institutionId, groupId, data)
services.institution.removeGroup(institutionId, groupId)
// Classrooms
services.institution.getClassrooms(institutionId, options?)
services.institution.getClassroomById(institutionId, classroomId)
services.institution.addClassroom(institutionId, data)
services.institution.updateClassroom(institutionId, classroomId, data)
services.institution.removeClassroom(institutionId, classroomId)
// Users & Registrations
services.institution.getUsers(institutionId, options?)
services.institution.getRegistrations(institutionId)
services.institution.getRegistrationById(institutionId, registrationId)
services.institution.getRegistrationByUserId(institutionId, userId)
services.institution.registerUser(institutionId, data)
services.institution.updateRegistration(institutionId, registrationId, data)
services.institution.assignUserToClassroom(institutionId, registrationId, data)
services.institution.removeRegistration(institutionId, registrationId)
services.institution.getGroupUsers(institutionId)ClassroomService
services.classroom.getAll() // List all classrooms
services.classroom.getById(id) // Get classroom by ID
services.classroom.getByInstitution(institutionId, params?)
services.classroom.create(data) // Create classroom
services.classroom.update(id, data) // Update classroom
services.classroom.delete(id) // Delete classroomShiftService
services.shift.getAll() // List all shifts
services.shift.getById(id) // Get shift by ID
services.shift.create(data) // Create shift
services.shift.update(id, data) // Update shift
services.shift.delete(id) // Delete shiftSerieService
services.serie.getAll() // List all series
services.serie.getById(id) // Get serie by ID
services.serie.create(data) // Create serie
services.serie.update(id, data) // Update serie
services.serie.delete(id) // Delete serieOrganizationService
services.organization.getAll(params?) // List with filters (name, type, isActive, etc.)
services.organization.getById(id) // Get organization by ID
services.organization.create(body) // Create organization
services.organization.update(id, body) // Update organization
services.organization.delete(id) // Delete organizationReportService
// Dashboard
services.report.getDashboard(params?)
services.report.getDashboardByInstitution(id)
// Courses by Area
services.report.getCoursesByArea()
services.report.getCoursesByAreaByInstitution(id)
// Adhesion Rate
services.report.getAdhesionRate()
services.report.getAdhesionRateByInstitution(id)
// Recent Activities
services.report.getRecentActivities(params?) // period: '7days' | '30days' | 'all'
services.report.getRecentActivitiesByInstitution(id, params?)
// Top Students
services.report.getTopStudents(params) // filterType: 'nota' | 'engajamento' | 'conclusao'
services.report.getTopStudentsByInstitution(id, params)GuardianService
services.guardian.getAll() // List all guardians
services.guardian.getById(id) // Get guardian by ID
services.guardian.create(data) // Create guardian
services.guardian.update(id, data) // Update guardian
services.guardian.delete(id) // Delete guardian
services.guardian.getUsers(id) // Get guardian's students
services.guardian.assignToUser(data) // Assign guardian to user
services.guardian.removeFromUser(guardianId, userId)Roles
Pre-defined role constants for consistent role checking.
import { GLOBAL_ROLES, DASHBOARD_ROLES, BACKOFFICE_ROLES } from 'academe-kit';
// Available global roles
GLOBAL_ROLES.ADMIN_ACADEME // 'admin_academe'
GLOBAL_ROLES.SCHOOL_ADMIN // 'school_admin'
GLOBAL_ROLES.TEACHER // 'teacher'
GLOBAL_ROLES.STUDENT // 'student'
GLOBAL_ROLES.GUARDIAN // 'guardian'Usage with protected components:
import { ProtectedComponent, GLOBAL_ROLES } from 'academe-kit';
<ProtectedComponent requiredRealmRoles={[GLOBAL_ROLES.ADMIN_ACADEME]}>
<AdminContent />
</ProtectedComponent>UI Components
Button
import { Button } from 'academe-kit';
<Button variant="primary" size="md" onClick={handleClick}>
Click me
</Button>
// Variants: 'primary' | 'secondary' | 'outline'
// Sizes: 'sm' | 'md' | 'lg'Spinner
import { Spinner } from 'academe-kit';
<Spinner />Utility: cn
Class name utility combining clsx and tailwind-merge:
import { cn } from 'academe-kit';
<div className={cn('base-class', isActive && 'active-class', className)} />Types
All types are exported for TypeScript support:
import type {
// Auth types
AcademeUser,
SecurityContextType,
KeycloakUser,
SecurityProviderProps,
AcademeKeycloakContextProps,
// Component props
ButtonProps,
// API types
types, // Entity types (User, Institution, Classroom, etc.)
apiTypes, // Full OpenAPI-generated types
} from 'academe-kit';Entity Types
import { types } from 'academe-kit';
type User = types.User;
type Institution = types.Institution;
type Classroom = types.Classroom;
type Organization = types.Organization;
type Serie = types.Serie;
type Shift = types.Shift;Development
# Install dependencies
npm install
# Run Storybook for component development
npm run dev
# Build the library
npm run build
# Build with watch mode
npm run build:watch
# Build Storybook static site
npm run build-storybook
# Generate API types from OpenAPI spec (requires API running locally)
npm run generate:api-typesProject Structure
src/
├── components/ # UI components
│ ├── Button/
│ ├── ProtectedApp/
│ ├── ProtectedComponent/
│ ├── ProtectedRouter/
│ └── ui/
├── context/ # React context providers
│ └── SecurityProvider/
├── services/ # API services
├── roles/ # Role definitions
├── types/ # TypeScript types
├── lib/ # Utilities
└── index.ts # Main entry pointLicense
MIT
Made with care by Academe
