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

@medipha/chat

v1.0.60

Published

Embeddable Medic-ERP chat module for React applications.

Readme

@medipha/chat

@medipha/chat is an embeddable React chat module for Medic-ERP. It uses the ERP application's React tree, BrowserRouter, authentication, and Ant Design 4 installation; it does not use an iframe or create a router.

Install

pnpm add @medipha/chat

Mount in Medic-ERP

The ERP imports the Ant Design 4 stylesheet exactly once, at its application entry point. The chat library deliberately does not import it.

import 'antd/dist/antd.css';
import { ChatModule } from '@medipha/chat';
import '@medipha/chat/styles.css';

<Route
  path="/chat-erp/*"
  element={
    <ChatModule
      userId={currentUserId}
      accessToken={accessToken}
      expireTime={expireTime}
      apiUrl={CHAT_API_URL}
      socketUrl={CHAT_SOCKET_URL}
      hasAddGroupVerified={permissions.addGroupVerified}
      hasUpdateGroupVerified={permissions.updateGroupVerified}
      hasDeleteGroupVerified={permissions.deleteGroupVerified}
      onUnauthorized={handleUnauthorized}
      onRefreshToken={handleRefreshToken}
      onNavigateOutsideChat={handleNavigateOutsideChat}
    />
  }
/>;

The ERP must own the surrounding BrowserRouter. ChatModule adds only relative routes: /chat-erp for the conversation list and /chat-erp/:conversationId for a room.

ChatModuleProps

| Prop | Required | Meaning | | ------------------------ | -------- | ------------------------------------------------------------- | | userId | Yes | ERP id of the signed-in user, as the chat backend knows them. | | accessToken | Yes | Current ERP access token used by chat API/socket clients. | | expireTime | Yes | Token expiry as epoch seconds for media upload checks. | | apiUrl | Yes | Base URL for the Chat HTTP API. | | socketUrl | Yes | Socket server URL. | | hasAddGroupVerified | Yes | May the user create a verified ("tích xanh") group. | | hasUpdateGroupVerified | Yes | May the user rename/re-avatar a verified group. | | hasDeleteGroupVerified | Yes | May the user disband a verified group. | | onUnauthorized | No | ERP callback for an unauthorized chat response. | | onRefreshToken | No | Returns a fresh token before media upload when expiry is near. | | onNavigateOutsideChat | No | ERP callback for navigation that leaves chat. |

accessToken, apiUrl and socketUrl are asserted non-empty at mount and throw otherwise, so render chat only once the ERP session is resolved.

Pass a new accessToken prop whenever ERP refreshes its credential. ChatModule updates its internal runtime context from the new prop and never writes a token to localStorage or sessionStorage.

Anchored widget

ChatWidget is the second entry point: a rail the ERP anchors to the right edge of the shell, plus a floating chat window. It takes every ChatModuleProps field and does not use the router, so it can be mounted in the ERP layout outside any <Routes>.

import { ChatWidget } from '@medipha/chat';

const [isChatOpen, setIsChatOpen] = useState(true);
const isChatFullPage = location.pathname.startsWith('/chat-erp');

<aside className="erp-chat-rail" hidden={!isChatOpen || isChatFullPage}>
  <ChatWidget
    {...chatRuntimeProps}
    isOpen={isChatOpen && !isChatFullPage}
    onRequestClose={() => setIsChatOpen(false)}
    onUnreadTotalChange={setChatUnreadTotal}
    onOpenFullPage={(conversationId) =>
      navigate(conversationId ? `/chat-erp/${conversationId}` : '/chat-erp')
    }
  />
</aside>;

The ERP owns the rail's box — size it 72px wide and full height. Keep the widget mounted while hidden and switch isOpen instead of unmounting: the conversation list stays warm and onUnreadTotalChange keeps feeding the ERP's own unread badge.

| Prop | Meaning | | -------------------------- | --------------------------------------------------------------------------- | | isOpen | Host is showing the widget. Defaults to true. Withholds the chat window. | | onRequestClose | The rail's close button was pressed; hide the rail. Omit to hide the button. | | onOpenFullPage | The window's expand button was pressed; route to the full-page chat. | | onUnreadTotalChange | Total unread across conversations, for the ERP's launcher badge. | | onActiveConversationChange | Which conversation the widget currently has open, or undefined. | | onExpandChange | The rail widened to the full sidebar (320px) or collapsed back to 72px. |

The rail's expanded state anchors itself to the viewport (position: fixed), so it works whether or not the ERP reacts to onExpandChange — but a host that hides the rail by collapsing its width must hide it with visibility, display or hidden rather than overflow, which does not clip fixed children.

The floating window is portalled to document.body at z-index: 1000; ERP chrome that must sit above chat needs a higher value.

Widget CSS variables

Set these on any ancestor to retune the widget without a rebuild:

| Variable | Default | | ------------------------------------- | ------- | | --med-chat-widget-window-width | 360px | | --med-chat-widget-window-height | 480px | | --med-chat-widget-window-right | 88px | | --med-chat-widget-window-bottom | 24px | | --med-chat-widget-window-z | 1000 | | --med-chat-widget-rail-expanded-width | 320px | | --med-chat-widget-image-width | 180px | | --med-chat-widget-image-height | 240px |

Nginx SPA fallback

Configure the ERP server so deep links under /chat-erp/* return the ERP application entry file:

location / {
  try_files $uri $uri/ /index.html;
}

Development and validation

Vite 8 requires Node.js 20.19+ or 22.12+.

pnpm install
pnpm dev

pnpm dev opens the root development playground. It loads ChatModule directly from src, so library code and CSS changes use Vite HMR without a library build after every edit. The playground's BrowserRouter is development-only; it is not part of the published package.

To validate the publishable library:

pnpm typecheck
pnpm build
npm pack --dry-run

To verify the CRA host after building the library:

cd examples/erp-host
pnpm install
pnpm build

Publish

Publish @medipha/chat-core before @medipha/chat. GitLab CI uses a masked, protected NPM_TOKEN variable with npm publish permission and runs only for a version tag such as v0.1.0. Update versions using semantic versioning: patch for fixes, minor for backward-compatible features, and major for breaking API changes. Create and push the version tag through your normal release process after reviewing the working tree.