chat-wrapper v1.0.19
A package wrapper around the React chat library, used to integrate chat into Vue and Angular apps.
Install
npm install chat-wrapper --saveAfter installing the wrapper, all the necessary packages for the chat will be automatically installed. Also, to integrate store chat into the application, you need to install reduxjs/toolkit:
npm install @reduxjs/toolkit --saveImports
Import the components and constants from the package into the file:
import { ChatConnector, ChatListConnector, LS_TOKEN_KEY, chatStore, ChatRootState } from "chat-wrapper";Important
After logging the user into your app, you should set the access token in the local storage of the browser for the chat components:
localStorage.setItem(LS_TOKEN_KEY, 'access_token');After calling the function to refresh a token from your app, the new received token must be installed in local storage of the browser under the key LS_TOKEN_KEY and returned from the function.
ChatConnector Component
import { ChatConnector } from "chat-wrapper";
<ChatConnector
opponent_id="opponent_id"
user_id="user_id"
user_locale="locale"
isOnlyChat={true}
cbHandleCloseChat={cbCloseChat}
handleRefreshToken={cbRefreshToken}
classHeader="customCSSClass"
classMessages="customCSSClass"
/>Chat props
| prop | default | type | description |
|---|---|---|---|
| opponent_id | none | string | User opponent ID |
| user_id | none | string | User id got from the access token by decoding |
| user_locale | ru/en | string | Chat interface language. The browser language is set by default |
| isOnlyChat | none | boolean | true value is set when only the chat close functionality is used. false allows more chat functionality |
| cbHandleCloseChat | none | function | A callback function that is called when the user clicks the close chat button |
| handleRefreshToken | none | function | An asynchronous callback function that is called if the chat API call returns an error. Takes an axios error as an argument. Should return the new user token |
| classHeader | " " | string | Adds a custom style class for the Chat header |
| classMessages | " " | string | Adds a custom style class for the box with messages |
ChatListConnector Component
import { ChatListConnector } from "chat-wrapper";
<ChatListConnector
user_id="user_id"
user_locale="locale"
isOnlyChatList={true}
cbHandleCloseChatList={handleCloseList}
handleRefreshToken={handleRefreshToken}
classList="customCSSClass"
cbHandleOpenChat={handleOpenChat}
/>ChatListConnector props
| prop | default | type | description |
|---|---|---|---|
| user_id | none | string | User id got from the access token by decoding |
| user_locale | ru/en | string | ChatList interface language. The browser language is set by default. |
| isOnlyChatList | none | boolean | true value is set when only the chat list close functionality is used. false allows more chat list functionality. |
| cbHandleCloseChatList | none | function | A callback function that is called when the user clicks the close chat button. |
| cbHandleOpenChat | none | function | A callback function that is called when the user clicks on a specific chat in the list. Takes an object as a function argument: {chat_id:string; opponent_id:string} |
| handleRefreshToken | none | function | An asynchronous callback function that is called if the chat API call returns an error. Takes an axios error as an argument. Should return the new user token. |
| classList | " " | string | Adds a custom style class for the ChatList wrapper |
Integration into Vue project
Setting up configuration files
To integrate the React library into the project, you should configure vite to work with react and Vue:
npm install @vitejs/plugin-reactIn the vite.config.ts file, add a condition for processing files for React:
//vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [vue(), react()],
});Connecting redux store
A store redux plugin is being created to connect chat to the store project:
//storePlugin.ts
import { App, reactive } from "vue";
import { EnhancedStore } from "@reduxjs/toolkit";
import { ChatRootState } from "chat-wrapper"; //type for store chat
export const storeKey = Symbol("Redux-Store");
export const createRedux = (store: EnhancedStore) => {
const rootStore = reactive<{ state: ChatRootState }>({
state: store.getState(),
});
const plugin = {
install: (app: App) => {
app.provide<{ state: ChatRootState }>(storeKey, rootStore);
store.subscribe(() => {
rootStore.state = store.getState();
});
},
};
return plugin;
};In the main.ts file of the app, the chat store and plugin are imported, then connected to the app for use:
//main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { createRedux } from "./storePlugin";
import { chatStore } from "chat-wrapper";
const app = createApp(App);
app.use(createRedux(chatStore)); // Connect the plugin from Redux Store in the app
app.mount("#app");Using Connectors
A component is created into which the chat connector from the wrapper package will be imported:
//ChatComponent.vue
<template>
<div id="app"></div>
</template>
<script lang="ts">
import { onBeforeUnmount, onMounted } from "vue";
import { LS_TOKEN_KEY, ChatConnector} from "chat-wrapper";
export default {
name: "ChatComponent",
setup() {
let reactComponent: InstanceType<typeof ChatConnector> | null = null;
onMounted(() => {
const appElement = document.getElementById("app") as HTMLElement;
reactComponent = new ChatConnector(appElement);
localStorage.setItem(LS_TOKEN_KEY, 'access_token');
reactComponent.render({
opponent_id: "opponent_id",
cbHandleCloseChat: () => {},
handleRefreshToken: () => {},
user_locale: "user_locale",
isOnlyChat: true,
user_id: "user_id",
});
});
onBeforeUnmount(() => {
if (reactComponent) {
reactComponent.unmount();
}
});
return {};
},
};
</script>And for the chat list connector the example would look like this:
//ChatListComponent.vue
<template>
<div id="app"></div>
</template>
<script lang="ts">
import { onBeforeUnmount, onMounted } from "vue";
import { LS_TOKEN_KEY, ChatListConnector } from "chat-wrapper";
export default {
name: "ChatListComponent",
setup() {
let reactComponent: InstanceType<typeof ChatListConnector> | null = null;
onMounted(() => {
const appElement = document.getElementById("app") as HTMLElement;
reactComponent = new ChatListConnector(appElement);
localStorage.setItem(LS_TOKEN_KEY, 'access_token');
reactComponent.render({
cbHandleOpenChat: () => {},
cbHandleCloseChatList: () => {},
handleRefreshToken: () => {},
user_locale: "user_locale",
isOnlyChatList: true,
user_id: "user_id",
});
});
onBeforeUnmount(() => {
if (reactComponent) {
reactComponent.unmount();
}
});
return {};
},
};
</script>In the App.vue project file you need to import the chat files:
//App.vue
<template>
<div>
<ChatComponent />
</div>
</template>
<script>
import ChatComponent from "./components/ChatComponent.vue";
import ChatListComponent from "./components/ChatListComponent.vue";
export default {
name: "App",
components: {
ChatComponent, ChatListComponent
},
};
</script>Integration into Angular project
Setting up configuration files
In order to be able to create files with the .tsx extension, you need to make changes to the tsconfig.json file:
//tsconfig.json
{
"compilerOptions": {
...
"jsx": "react"
},
"angularCompilerOptions": {
...
}
}Connecting redux store
You should import the chat store and connect it to the project; to do this, you should create the file src/redux-store.service.ts
//src/redux-store.service.ts
import { Injectable } from '@angular/core';
import { chatStore } from 'chat-wrapper';
@Injectable({
providedIn: 'root',
})
export class ReduxStoreService {
getStore() {
return chatStore;
}
}Using Connectors
Create a component file into which you will import the chat connectors:
//ChatWrapper.tsx
import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
Input,
OnChanges,
OnDestroy,
Output,
SimpleChanges,
ViewChild,
ViewEncapsulation,
} from "@angular/core";
import { LS_TOKEN_KEY, ChatConnector } from "chat-wrapper";
import { createRoot } from "react-dom/client";
const containerElementRef = "customReactComponentContainer";
@Component({
selector: "chat-wrapper",
template: `<div #${containerElementRef}></div>`,
encapsulation: ViewEncapsulation.None,
})
export class ChatWrapper implements OnChanges, OnDestroy, AfterViewInit {
@ViewChild(containerElementRef, { static: true }) containerRef!: ElementRef;
@Output() public componentClick = new EventEmitter<void>();
@Input() opponentId: string = "opponent_id";
@Input() userId: string = "user_id";
@Input() userLocale: string = "user_locale";
@Input() isOnlyChat: boolean = true;
private root: ReturnType<typeof createRoot> = {} as ReturnType<
typeof createRoot
>;
private chatConnector!: InstanceType<typeof ChatConnector>;
ngOnChanges(changes: SimpleChanges): void {
if (this.chatConnector) {
this.render();
}
}
ngAfterViewInit() {
this.chatConnector = new ChatConnector(this.containerRef.nativeElement);
this.render();
}
ngOnDestroy() {
if (this.chatConnector) {
this.chatConnector.unmount();
}
}
private render() {
localStorage.setItem(LS_TOKEN_KEY, 'access_token');
this.chatConnector.render({
opponent_id: this.opponentId,
user_id: this.userId,
user_locale: this.userLocale,
isOnlyChat: this.isOnlyChat,
cbHandleCloseChat: () => {
this.componentClick.emit();
},
handleRefreshToken: () => {},
});
}
}Then you should import the chat wrapper component into the app files:
// app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ChatWrapper } from '../ChatWrapper';
@Component({
selector: 'app-root',
imports: [RouterOutlet, ChatWrapper],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
...
}// app/app.component.html
<chat-wrapper></chat-wrapper>
<router-outlet />10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago