npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ubkinfotech/student-erp

v0.2.21

Published

UBK ERP enterprise-grade modular Student ERP foundation for React Native

Downloads

208

Readme

@ubkinfotech/student-erp

Enterprise-grade, modular Student ERP foundation for React Native. Designed for production apps that want reusable ERP screens and API logic without coupling to the host app’s navigation or Redux setup.

  • Framework: React Native (Metro)
  • HTTP: Axios (shared client via provider)
  • Data fetching: React Query
  • Authentication: external token injection (no Bearer by default)
  • Modules: Transport, TimeTable, Notes, Syllabus, Homework, Attendance, NoticeBoard, Subject, Teacher

Install

npm i @ubkinfotech/student-erp

Requirements

  • Your app must already include React Query:
npm i @tanstack/react-query
  • For some modules, the host app must install these libraries (they are not bundled):
    • Homework upload: react-native-document-picker, react-native-image-picker
    • Attendance calendar: react-native-calendars

Provider

All modules use a shared Axios client created by ERPProvider.

Basic

import React from 'react';
import {ERPProvider} from '@ubkinfotech/student-erp';

export function AppRoot() {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken} fileBaseUrl={FILE_BASE_URL}>
      <App />
    </ERPProvider>
  );
}

Branch-aware file provider

For Homework, Notes, and Syllabus attachments uploaded through the public image server, pass a branch-aware file base URL and schoolCode.

import React from 'react';
import {ERPProvider} from '@ubkinfotech/student-erp';

export function AppRoot({authToken, branchId}: any) {
  const staticSchoolDownloadBase = `${IMAGE_BASE_URL}/uploads/school_${branchId}/`;

  return (
    <ERPProvider
      baseUrl={API_BASE_URL}
      authToken={authToken}
      fileBaseUrl={staticSchoolDownloadBase}
      schoolCode={branchId}>
      <App />
    </ERPProvider>
  );
}

Async token callback

import React from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {ERPProvider} from '@ubkinfotech/student-erp';

export function AppRoot() {
  return (
    <ERPProvider baseUrl={API_BASE_URL} getAuthToken={() => AsyncStorage.getItem('token')}>
      <App />
    </ERPProvider>
  );
}

Module Imports

import {
  ERPProvider,
  AttendanceByDayScreen,
  AttendanceMonthlyScreen,
  HomeworkScreen,
  LibraryIssuedBooksScreen,
  NoticeBoardScreen,
  NotesScreen,
  StudentRouteDetailsScreen,
  SubjectScreen,
  SyllabusScreen,
  TeacherScreen,
  TimeTableScreen,
} from '@ubkinfotech/student-erp';

Tested Integration (Reference)

The modules are verified inside the host app using a “switcher” screen:

Branch ID

The host app should pass the school branch id to the module for branch-aware file URLs.

  • Recommended source: login response fk_createdby
  • Common fallback chain used in the host app:
    • user?.fk_createdby || user?.branch_id || user?.branchID || user?.branchId

Host URL Helper

The host app can use one shared helper, like SampleNpm.jsx, to build module file URLs from a single branch-aware base:

const branchId = 82;
const staticSchoolDownloadBase = `${IMAGE_BASE_URL}/uploads/school_${branchId}/`;

const buildStaticAttachmentUrl = (fileName: string, modulePath: string) => {
  const normalized = String(fileName || '').replace(/\\/g, '/').replace(/^\/+/, '');

  if (!normalized) {
    return '';
  }

  if (/^https?:\/\//i.test(normalized)) {
    return normalized;
  }

  if (normalized.startsWith('school_')) {
    return `${IMAGE_BASE_URL}/uploads/${normalized}`;
  }

  if (normalized.startsWith('uploads/')) {
    return `${staticSchoolDownloadBase}${normalized.replace(/^uploads\//, '')}`;
  }

  if (normalized.startsWith(`${modulePath}/`)) {
    return `${staticSchoolDownloadBase}${normalized}`;
  }

  return `${staticSchoolDownloadBase}${modulePath}/${normalized}`;
};

Examples

Transport

import React from 'react';
import {ERPProvider, StudentRouteDetailsScreen} from '@ubkinfotech/student-erp';

export function TransportExample() {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken} fileBaseUrl={FILE_BASE_URL}>
      <StudentRouteDetailsScreen />
    </ERPProvider>
  );
}

TimeTable

import React from 'react';
import {ERPProvider, TimeTableScreen} from '@ubkinfotech/student-erp';

export function TimeTableExample({classId, sectionId, sessionId}: any) {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken}>
      <TimeTableScreen classId={classId} sectionId={sectionId} sessionId={sessionId} />
    </ERPProvider>
  );
}

Notes (View + Download)

Notes supports inline image/PDF viewing inside the module, but the host app can still provide callbacks for opening files and downloading files. For public uploaded files, pass branchId, schoolCode, and staticSchoolDownloadBase.

import React from 'react';
import {Alert, Platform, ToastAndroid} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import ImageView from 'react-native-image-viewing';
import RNFetchBlob from 'react-native-blob-util';
import {ERPProvider, NotesScreen} from '@ubkinfotech/student-erp';

export function NotesExample() {
  const navigation = useNavigation();
  const branchId = user?.fk_createdby || user?.branch_id || user?.branchID || user?.branchId || 82;
  const staticSchoolDownloadBase = `${IMAGE_BASE_URL}/uploads/school_${branchId}/`;

  const openFile = ({url, extension, name}: any) => {
    if (extension === 'pdf') {
      navigation.navigate('FeesReport', {filepath: url, name: name || 'File'});
      return;
    }
    if (['jpg', 'jpeg', 'png', 'webp'].includes(String(extension).toLowerCase())) {
      Alert.alert('Image', 'Open image preview in your screen using ImageView');
      return;
    }
    Alert.alert('Unsupported File', 'This file type is not supported for direct viewing.');
  };

  const downloadFile = async ({url, filename}: any) => {
    if (Platform.OS === 'android') {
      ToastAndroid.showWithGravityAndOffset('Downloading Started !', ToastAndroid.LONG, ToastAndroid.BOTTOM, 25, 50);
    }
    const docPath = RNFetchBlob.fs.dirs.DocumentDir;
    await RNFetchBlob.config({
      path: `${docPath}/${filename}`,
      fileCache: true,
      addAndroidDownloads: {
        useDownloadManager: true,
        notification: true,
        title: filename,
        description: filename,
        storeInDownloads: true,
      },
    }).fetch('GET', url);
  };

  return (
    <ERPProvider
      baseUrl={API_BASE_URL}
      authToken={authToken}
      fileBaseUrl={staticSchoolDownloadBase}
      schoolCode={branchId}>
      <NotesScreen
        branchId={branchId}
        onOpenFile={({url, extension, item}) => openFile({url, extension, name: item?.title})}
        onDownloadFile={({url, filename}) => downloadFile({url, filename})}
      />
    </ERPProvider>
  );
}

Syllabus

import React from 'react';
import {Alert} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import {ERPProvider, SyllabusScreen} from '@ubkinfotech/student-erp';

export function SyllabusExample({classId}: any) {
  const navigation = useNavigation();
  const branchId = user?.fk_createdby || user?.branch_id || user?.branchID || user?.branchId || 82;
  const staticSchoolDownloadBase = `${IMAGE_BASE_URL}/uploads/school_${branchId}/`;

  return (
    <ERPProvider
      baseUrl={API_BASE_URL}
      authToken={authToken}
      fileBaseUrl={staticSchoolDownloadBase}
      schoolCode={branchId}>
      <SyllabusScreen
        classId={classId}
        branchId={branchId}
        onOpenFile={({url, extension, item}) => {
          if (extension === 'pdf') {
            navigation.navigate('FeesReport', {filepath: url, name: item?.subject_title || 'Syllabus'});
            return;
          }
          if (['jpg', 'jpeg', 'png', 'webp'].includes(String(extension).toLowerCase())) {
            Alert.alert('Image', 'Open image preview in your screen using ImageView');
          }
        }}
      />
    </ERPProvider>
  );
}

Homework (List + Upload)

Homework supports upload internally. For branch-aware attachment URLs, pass branchId, schoolCode, and staticSchoolDownloadBase.

import React from 'react';
import {Alert, Platform, ToastAndroid} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import RNFetchBlob from 'react-native-blob-util';
import {ERPProvider, HomeworkScreen} from '@ubkinfotech/student-erp';

export function HomeworkExample() {
  const navigation = useNavigation();
  const branchId = user?.fk_createdby || user?.branch_id || user?.branchID || user?.branchId || 82;
  const staticSchoolDownloadBase = `${IMAGE_BASE_URL}/uploads/school_${branchId}/`;

  const downloadFile = async ({url, filename}: any) => {
    if (Platform.OS === 'android') {
      ToastAndroid.showWithGravityAndOffset('Downloading Started !', ToastAndroid.LONG, ToastAndroid.BOTTOM, 25, 50);
    } else {
      Alert.alert('Download', 'Downloading started');
    }

    const docPath = RNFetchBlob.fs.dirs.DocumentDir;
    await RNFetchBlob.config({
      path: `${docPath}/${filename}`,
      fileCache: true,
      addAndroidDownloads: {
        useDownloadManager: true,
        notification: true,
        title: filename,
        description: filename,
        storeInDownloads: true,
      },
    }).fetch('GET', url);
  };

  return (
    <ERPProvider
      baseUrl={API_BASE_URL}
      authToken={authToken}
      fileBaseUrl={staticSchoolDownloadBase}
      schoolCode={branchId}>
      <HomeworkScreen
        branchId={branchId}
        onOpenFile={({url, extension, item}) => {
          if (extension === 'pdf') {
            navigation.navigate('FeesReport', {filepath: url, name: item?.title || item?.name || 'Homework'});
            return;
          }
          if (['jpg', 'jpeg', 'png', 'webp'].includes(String(extension).toLowerCase())) {
            Alert.alert('Image', 'Open image preview in your screen using ImageView');
          }
        }}
        onDownloadFile={({url, filename}) => downloadFile({url, filename})}
      />
    </ERPProvider>
  );
}

Attendance (Calendar + Monthly)

import React from 'react';
import {ERPProvider, AttendanceByDayScreen, AttendanceMonthlyScreen} from '@ubkinfotech/student-erp';

export function AttendanceExample({studentId, sessionId}: any) {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken}>
      <AttendanceByDayScreen studentId={studentId} sessionId={sessionId} />
      <AttendanceMonthlyScreen studentId={studentId} sessionId={sessionId} />
    </ERPProvider>
  );
}

NoticeBoard (List + Details)

By default, details opens inside a modal. If you prefer navigation, use onOpenNotice.

import React from 'react';
import {ERPProvider, NoticeBoardScreen} from '@ubkinfotech/student-erp';

export function NoticeExample() {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken}>
      <NoticeBoardScreen />
    </ERPProvider>
  );
}

Subject

import React from 'react';
import {ERPProvider, SubjectScreen} from '@ubkinfotech/student-erp';

export function SubjectExample() {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken}>
      <SubjectScreen />
    </ERPProvider>
  );
}

Teacher

Teacher requires sessionId and uses fileBaseUrl for teacher images.

import React from 'react';
import {ERPProvider, TeacherScreen} from '@ubkinfotech/student-erp';

export function TeacherExample({sessionId}: any) {
  return (
    <ERPProvider baseUrl={API_BASE_URL} authToken={authToken} fileBaseUrl={FILE_BASE_URL}>
      <TeacherScreen sessionId={sessionId} />
    </ERPProvider>
  );
}

Notes on Authentication

The default header is:

  • Authorization: <token>

If your backend uses a different header shape, configure the provider using custom headers via headers in ERPProvider.