Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init Web SDK #2

Merged
merged 1 commit into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/web-sdk-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Web-SDK CI

on:
pull_request:
types: [opened, synchronize]
branches: [main]
paths:
- "web-sdk/**"
jobs:
build-and-test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x]

steps:
- uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm install --prefix web-sdk

- name: Build
run: npm run build --prefix web-sdk

- name: Run tests
run: npm test --prefix web-sdk
38 changes: 38 additions & 0 deletions web-sdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Dependency directories
node_modules

# Build outputs
dist
build
out
coverage

# System files
.DS_Store
Thumbs.db

# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# IDE/Editor folders
.vscode/
.idea/
*.swp
*.swo

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Optional npm cache directory
.npm


# Temporary folders
tmp/
temp/
159 changes: 159 additions & 0 deletions web-sdk/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<h1 align="center">
<a href="https://index.network/#gh-light-mode-only">
<img style="width:400px" src="https://index.network/images/IndexNetworkLogo.png">
</a>
<a href="https://index.network/#gh-dark-mode-only">
<img style="width:400px" src="https://index.network/images/IndexNetworkLogo-white.png">
</a>
</h1>
<p align="center">
<i align="center">Create and monetize interoperable discovery engines. 🚀</i>
</p>

<div align="center">

![CI](https://github.com/indexnetwork/index/actions/workflows/web-sdk-ci.yml/badge.svg)
[![npm version](https://img.shields.io/npm/v/index-chat.svg)](https://www.npmjs.com/package/index-chat)

![React](https://img.shields.io/badge/react-18.2-blue.svg)
![TypeScript](https://img.shields.io/badge/typescript-5.3-blue.svg)
![Babel](https://img.shields.io/badge/babel-7.23-blue.svg)
![Webpack](https://img.shields.io/badge/webpack-5.89-blue.svg)
![TailwindCSS](https://img.shields.io/badge/tailwindcss-3.4-blue.svg)

</div>

# IndexChat

IndexChat is a chat UI component specifically designed for interaction within the Index Network.

Super easy to integrate and offers a seamless experience, making it an ideal tool for:

- creators,
- communities,
- DAOs,
- brands,
- researchers, and many more


👉🏻 [View Demo](https://index-demo-eight.vercel.app)


Let's start building! ⛓️


<div>
<img alt="Demo Screen" style="width:500px" src="demo/ui-light.png#gh-light-mode-only" />
<img alt="Demo Screen" style="width:500px" src="demo/ui-dark.png#gh-dark-mode-only" />
</div>


## Features

- Easy to integrate with any React application
- Real-time chat capabilities powered by modern practices
- Responsive design and built-in dark mode
- Fully customizable themes


## Installation

Get the latest package via npm.

```bash
npm install @index-network/web-sdk
```

## Usage

Place `IndexChat` tag into your app with your `index_id`.

This code creates a button that handles all the configuration. Now you can click it to start chatting. No extra work is required. 🎉


```typescript
import IndexChat from '@index-network/web-sdk';

const App = () => {
return (
<div>
{/* Your components */}
<IndexChat id='index_id' />
</div>
);
};

export default App;
```


## Styling

IndexChat allows you to customize the theme by overriding the defaults for any provided value. Here's an example of how you can set a custom theme:


```typescript
const customStyle = {
darkMode: true,
theme: {
light: {
primary: '#0F172A',
secondary: '#475569',
accent: '#BED0EC',
background: '#FFFFFF',
border: '#E2E8F0',
pale: '#F8FAFC',
},
dark: {
primary: '#DFEAF4',
secondary: '#E7EEFF',
accent: '#1256A2',
background: '#0F172A',
border: '#314969',
pale: '#212C45',
},
}
};

const App = () => {
return (
<div>
{/* Your components */}
<IndexChat id='index_id' style={customStyle} />
</div>
);
};
```

### Fonts

The package uses `Inter` as the primary and `Freizeit` as the secondary font default. If you want to enable them, add the following line to your app.

```typescript
import '@index-network/web-sdk/dist/assets/style/fonts.css';
```


## Warnings and Compatibility

Before integrating `web-sdk` into your project, please consider the following:


### Requirements

- <b>React Version:</b> `web-sdk` uses version 18.2.0. Ensure that your project has a compatible version.

- The jsx option is set to `react-jsx`, which requires React 17+.

- <b>TypeScript Version:</b> The package is built with TypeScript 5.3.3. Projects using an older version might encounter compatibility issues.

- `web-sdk` is compiled as a UMD (Universal Module Definition) module. Ensure that your module bundler and environment are compatible with UMD modules.


## Contributing

Contributions are always welcome! Please read the contributing guidelines to get started.

## License

This project is licensed under the MIT License.
53 changes: 53 additions & 0 deletions web-sdk/__test__/components/AskInput.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import '@testing-library/jest-dom';
import { screen, fireEvent } from '@testing-library/react';
import AskInput from '../../src/components/AskInput';
import { renderComponent } from '../mocks/mockProviders';
import { mockChatData, mockThemeData } from '../mocks/mockData';

describe('AskInput', () => {
let chatData: any;
let themeData: any;

beforeEach(() => {
chatData = { ...mockChatData };
themeData = { ... mockThemeData };
jest.clearAllMocks();
});

it('renders input field and send button', () => {
renderComponent(chatData, themeData, AskInput);

expect(screen.getByLabelText('ask-input')).toBeInTheDocument();
expect(screen.getByRole('button')).toBeInTheDocument();
});

it('updates input value on change', () => {
renderComponent(chatData, themeData, AskInput);

const input = screen.getByLabelText('ask-input') as HTMLInputElement;
fireEvent.change(input, { target: { value: 'Test Query' } });
expect(input.value).toBe('Test Query');
});

it('calls sendMessage on send button click with non-empty input', () => {
chatData.sendMessage = jest.fn();
renderComponent(chatData, themeData, AskInput);

const input = screen.getByLabelText('ask-input');
fireEvent.change(input, { target: { value: 'Test Query' } });
fireEvent.click(screen.getByRole('button'));

expect(chatData.sendMessage).toHaveBeenCalledWith('Test Query');
});

it('calls sendMessage on enter key press with non-empty input', () => {
renderComponent(chatData, themeData, AskInput);

const input = screen.getByLabelText('ask-input');
fireEvent.change(input, { target: { value: 'Test Query' } });
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });

expect(chatData.sendMessage).toHaveBeenCalledWith('Test Query');
});

});
50 changes: 50 additions & 0 deletions web-sdk/__test__/components/ChatBody.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import '@testing-library/jest-dom';
import { screen } from '@testing-library/react';
import ChatBody from '../../src/components/ChatBody';
import { renderComponent } from '../mocks/mockProviders'
import { mockChatData, mockThemeData } from '../mocks/mockData';

describe('ChatBody', () => {
let chatData: any;
let themeData: any;

beforeEach(() => {
chatData = { ...mockChatData };
themeData = { ...mockThemeData };
jest.clearAllMocks();
});

it('renders messages correctly', () => {
renderComponent(chatData, themeData, ChatBody);

expect(screen.getByLabelText('chat-message')).toBeInTheDocument();
});

it('renders a placeholder when there are no messages', () => {
chatData.messages = [];
renderComponent(chatData, themeData, ChatBody);

expect(screen.getByLabelText('chat-body-placeholder')).toBeInTheDocument();
expect(screen.getByRole('img')).toBeInTheDocument();
});

it('renders user avatar in message - user', () => {
renderComponent(chatData, themeData, ChatBody);

expect(screen.getByAltText('Avatar')).toHaveAttribute('src', 'Test Avatar');
});

it('renders user avatar in message - user', () => {
chatData.userProfile = null;
renderComponent(chatData, themeData, ChatBody);

expect(screen.getByAltText('Avatar')).not.toHaveAttribute('src', 'Test Avatar');
});

it('renders assistant avatar in message - assistant', () => {
chatData.messages[0].role = 'assistant';
renderComponent(chatData, themeData, ChatBody);

expect(screen.getByAltText('Avatar')).toHaveAttribute('src', 'test-file-stub'); // check img file loader stub
});
});
Loading
Loading