npm package: @sigma-streaming/micro
Description: CMS micro frontend integration package
Author: Son Hong Do
Latest version: 1.1.3

# Sigma Streaming Micro Frontend

## Installation

npm
```sh
npm install @sigma-streaming/micro wujie-react
```
yarn
```sh
yarn add @sigma-streaming/micro wujie-react
```
pnpm
```sh
pnpm install @sigma-streaming/micro wujie-react
```


## Usage
[React demo]([https://](https://github.com/sondh0127/react-sigma-micro-demo))

### 1. Register Sigma Apps

**main.tsx**
```tsx
import type { AppConfig, MicroApp } from '@sigma-streaming/micro'
import { registerSigmaApps } from '@sigma-streaming/micro'

export const microApps: MicroApp[] = [
  {
    name: '@sigma-streaming/ssai',
    url: '//123.31.18.25:2181/micro/cms/ssai/',
  },
  {
    name: '@sigma-streaming/lrm',
    url: '//dev-livestream.gviet.vn/micro/cms/lrm/',
  },
]

const appConfig: AppConfig = {
  // generated token for sigma micro app
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  // token type
  tokenProp: 'x-backdoor',
  // App channel ID - Optional - For tokenType Bearer
  appId: 'c9c2ebfb-...',
}

export const actions = registerSigmaApps(microApps, appConfig)
```
### 2. Create component for Micro App

LrmApp.tsx
```tsx
import React from 'react'
import WujieReact from 'wujie-react'
import { useHistory, useLocation } from 'react-router-dom'

export default function LrmApp(
  {
    url = '//dev-livestream.gviet.vn/micro/cms/lrm/',
    name = '@sigma-streaming/lrm'
  }: MicroProps) {
  const location = useLocation()
  // const navigation = useNavigate(); // new react-router
  const history = useHistory()
  const mainPath = '/lrm'
  const subPath = '/lrm-sub'
  const path = location.pathname.replace(subPath, '').replace(mainPath, '').replace('/', '')
  const viteUrl = url + path

  const props = {
    jump: (newRoute) => {
      history.replace(`/${newRoute}`)
    },
  }

  return (
    // Single mode, Name is the same to reuse an unbounded instance,
    // changing the URL sub-application re-rendering instance to the corresponding routing
    <WujieReact
      width="100%"
      height="100%"
      name={name}
      url={viteUrl}
      sync={true}
      props={props}
    ></WujieReact>
  )
}

```
### 3. Create container and add route corresponding for each app's activeRule

*** Note: We use tailwind css class to demonstrate layout styling
App.tsx
```tsx
import { Route, HashRouter as Router, Switch } from 'react-router-dom'
import { CONTAINER } from './main'
import LrmApp from './LrmApp'

// Usecase 1: Main path
<div className="relative my-[-15px] min-h-[calc(100vh-45px)] mx-[-20px]">
  <Switch>
    <Route exact path="/lrm"><LrmApp /></Route>
    <Route exact path="/ssai"></Route>
  </Switch>
</div>

// Usecase 2: With sub path
<div className="relative my-[-15px] min-h-[calc(100vh-45px)] mx-[-20px]">
  <Switch>
    <Route exact path="/lrm"><LrmApp /></Route>
    <Route exact path="/lrm-sub/:path"><LrmApp /></Route>
    <Route exact path="/ssai"></Route>
  </Switch>
</div>


// Usecase 3: Sub path only
<div className="relative my-[-15px] min-h-[calc(100vh-45px)] mx-[-20px]">
  <Switch>
    <Route exact path="/lrm-sub/:path"><LrmApp /></Route>
    <Route exact path="/ssai-sub/:path"></Route>
  </Switch>
</div>
```

### 4. Add routing to each app to your Main Sidebar
Each app expose a routes and list

Sidebar.tsx
```tsx
import type { GlobalState } from '@sigma-streaming/micro'
import type { MenuProps } from 'antd'
import { Menu } from 'antd'
import { actions } from './main'

const Sidebar = (props: SidebarProps) => {
  const history = useHistory()
  const [state, setState] = useState<GlobalState>()

  useEffect(() => {
    const cleanUp = actions.onStateChange((newState) => {
      setState(newState)
    })
    return () => { cleanUp() }
  }, [])

  // Render sidebar from state children
  // Ant design example

   type MenuItem = Required<MenuProps>['items'][number]

   function getItem(
     label: React.ReactNode,
     key: React.Key,
     icon?: React.ReactNode,
     children?: MenuItem[],
     type?: 'group',
   ): MenuItem {
     return {
       key,
       icon,
       children,
       label,
       type,
     } as MenuItem
   }

   const memoItems = useMemo(() => {
     const items: MenuProps['items'] = (state?.children || []).map(item =>
       getItem(item.name, item.name, <div className="i-ant-design:mail-filled" />,
         item.routes.map(route => getItem(route.meta.title, route.path, <div className={route.meta.icon} />))
       ),
     )
     return items
   }, [state])

   const onClick: MenuProps['onClick'] = (e) => {
     const path = `/${e.keyPath[1]}-sub${e.keyPath[0]}`
     if (e.keyPath)
       history.push(path)
   }

   return (
    <Menu
      className="flex-1"
      onClick={onClick}
      style={{ width: 220 }}
      mode="inline"
      items={memoItems}
    />
   )
}
```