Skip to content
Open
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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
.env
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Use Node.js LTS as base image
FROM node:18

# Set the working directory inside the container
WORKDIR /app

# Copy package.json and package-lock.json to install dependencies first (caching optimization)
COPY package.json package-lock.json ./

# Install dependencies
RUN npm install

# Copy the rest of the project files
COPY . .

# Build the React app
RUN npm run build

# Serve the app using a lightweight HTTP server
RUN npm install -g serve
CMD ["npm","start"]

# Expose port 3000
EXPOSE 3000
110 changes: 26 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ The application consists of three main components:
## 💡 Core Features

### Chat Interface

![Chat Interface Screenshot](./assets/interface.png)

- Real-time message thread
- Speech-to-text input support
- Theme switching (dark/light mode)
- Quick reply suggestions
Expand All @@ -45,109 +41,55 @@ While you have 24 hours to submit, the challenge is designed for 2 hours of focu
## 📋 Repository Structure

```
your-solution/
app/
├──cypress/
│ ├── e2e
│ ├── fixtures/
│ ├── screenshots/
├── src/
│ ├── components/
│ ├── hooks/
│ ├── pages/
│ ├── context/
│ ├── services/
│ ├── utils/
│ └── types/
├── Dockerfile
├── docker-compose.yml
└── README.md
```

## 🚀 Getting Started
## Open Project

1. Clone this repository
2. Review specifications.md
3. Implement your solution
4. Test and document
5. Submit your repository

## 🐳 Docker Setup

Your solution must include proper Docker configuration:

```yaml
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
```

## 📮 Submission Requirements

1. Public GitHub repository
2. Complete source code
3. Docker configuration
4. Comprehensive README
5. Implementation documentation

### Required Documentation
2. Install Node
3. run npm i
4. run npm run dev

1. Setup instructions
2. Architecture overview
3. Implementation decisions
4. Testing approach
## Architechture:
The architecture of the project follows a structured and modular approach to ensure scalability and maintainability. The application starts with the Home Page, which serves as the main interface for users to interact with the chat system. At its core, the application consists of a Message Window, where conversations take place. The UI is broken down into distinct components:

## 🎯 Evaluation Criteria
Header – Contains the Settings button, allowing users to configure preferences such as language, speech enablement, and theme switching.
Main Message Window – Displays user and AI-generated messages in a scrollable chat interface, ensuring smooth UX with animations.
Suggestion Panel – Provides quick reply suggestions, enhancing user interaction.
Input Form – Includes a text input field for typing messages and a microphone button for voice-based input.
For speech functionality, the app integrates the Web Speech API, enabling speech-to-text conversion for voice messages. The microphone button allows users to speak instead of typing, making the app more accessible.
Settings Panel: All the settings are stores in local storage so that they persists.

### Technical Excellence (40%)
## Tailwind:
Used for styling and then using tailwind and context API we toggle between dark and light mode

- Code quality and organization
- React patterns implementation
- Performance optimization
- Error handling
- Testing approach
## Vite:
Bundler used for creating react app

### Feature Implementation (30%)
## Cypress:
Used for end to end testing

- Chat interface functionality
- Speech recognition integration
- State management
- Theme implementation
- Responsive design

### Best Practices (30%)
# I have also used mock data to show how the chat looks.

- Documentation quality
- Git practices
- Docker configuration
- Code organization
- Development setup

## 🎯 Success Criteria

Your solution should demonstrate:

- Clean, maintainable React code
- Modern component architecture
- Thoughtful state management
- Professional documentation
- Smooth user experience

## 🚀 Running Your Solution

```bash
# Clone repository
git clone [your-repository-url]

# Navigate to project
cd [project-directory]

# Start with Docker
docker-compose up

# Access application
open http://localhost:3000
```

## 🤝 Questions?

For any clarifications, feel free to reach out via LinkedIn.

Ready to showcase your React expertise? Let's see what you can build! 🚀
9 changes: 9 additions & 0 deletions cypress.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { defineConfig } = require("cypress");

module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// Add Cypress plugins here
},
},
});
38 changes: 38 additions & 0 deletions cypress/e2e/app-test.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
describe('Check the end to end stories', () => {
beforeEach(() => {
cy.visit('http://localhost:3000')
})

it('display chat box', () => {
cy.get('.chat-box')
})

it('should navigate to settings', () => {
cy.get('.settings').click()
cy.url().should('include', '/settings')
})


it('should navigate to settings', () => {
cy.get('.suggestions').children().should('have.length', 3)
})

it('typing in text box the message should be added', () => {
cy.intercept(
{ method: "POST", url: "https://run.mocky.io/v3/093fc88b-1c4f-4cff-96bb-72f84dcbc2f4" },
{
data: {
"id": "23d878e0-50f2-45a0-96db-af4a3db32ca8",
"content": "dolorum error maiores",
"timestamp": "2025-02-10T20:19:41.217Z",
"type": "\"ai\""
}
}
)
cy.get('.input-box').type("hey hello")
cy.get('.send-btn').click()
cy.wait(2000)
cy.get('.all-messages').children().should('have.length', 5)
})

})
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
37 changes: 37 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
17 changes: 17 additions & 0 deletions cypress/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'
10 changes: 10 additions & 0 deletions docker.compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "3.8"
services:
react-app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
command: [ "npm", "start" ]
28 changes: 28 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading