Skip to content

Commit

Permalink
feat: add new chat dialog in chats page (#90)
Browse files Browse the repository at this point in the history
* feat: create conversation dialog

* chore: format codes

* chore: format code

* chore: update ts-unused-vars rule in eslint

* refactor: extract chat types into a file

* refactor: rename and update position of new-chat

* fix: update text color

---------

Co-authored-by: satnaing <[email protected]>
  • Loading branch information
AliAkrem and satnaing authored Feb 4, 2025
1 parent fd9b761 commit 93be363
Show file tree
Hide file tree
Showing 4 changed files with 338 additions and 141 deletions.
13 changes: 13 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ export default tseslint.config(
{ allowConstantExport: true },
],
'no-console': 'error',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
},
}
)
138 changes: 138 additions & 0 deletions src/features/chats/components/new-chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { useEffect, useState } from 'react'
import { IconCheck, IconX } from '@tabler/icons-react'
import { toast } from '@/hooks/use-toast'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/components/ui/command'
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import { ChatUser } from '../data/chat-types'

type User = Omit<ChatUser, 'messages'>

type Props = {
users: User[]
open: boolean
onOpenChange: (open: boolean) => void
}
export function NewChat({ users, onOpenChange, open }: Props) {
const [selectedUsers, setSelectedUsers] = useState<User[]>([])

const handleSelectUser = (user: User) => {
if (!selectedUsers.find((u) => u.id === user.id)) {
setSelectedUsers([...selectedUsers, user])
} else {
handleRemoveUser(user.id)
}
}

const handleRemoveUser = (userId: string) => {
setSelectedUsers(selectedUsers.filter((user) => user.id !== userId))
}

useEffect(() => {
if (!open) {
setSelectedUsers([])
}
}, [open])

const onSubmit = () => {
toast({
title: 'You submitted the following values:',
description: (
<pre className='mt-2 w-[340px] rounded-md bg-slate-950 p-4'>
<code className='text-white'>
{JSON.stringify(selectedUsers, null, 2)}
</code>
</pre>
),
})
}

return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className='sm:max-w-[600px]'>
<DialogHeader>
<DialogTitle>New message</DialogTitle>
</DialogHeader>
<div className='flex flex-col gap-4'>
<div className='flex flex-wrap items-center gap-2'>
<span className='text-sm text-zinc-400'>To:</span>
{selectedUsers.map((user) => (
<Badge key={user.id} variant='default'>
{user.fullName}
<button
className='ml-1 rounded-full outline-none ring-offset-background focus:ring-2 focus:ring-ring focus:ring-offset-2'
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleRemoveUser(user.id)
}
}}
onClick={() => handleRemoveUser(user.id)}
>
<IconX className='h-3 w-3 text-muted-foreground hover:text-foreground' />
</button>
</Badge>
))}
</div>
<Command className='rounded-lg border'>
<CommandInput
placeholder='Search people...'
className='text-foreground'
/>
<CommandList>
<CommandEmpty>No people found.</CommandEmpty>
<CommandGroup>
{users.map((user) => (
<CommandItem
key={user.id}
onSelect={() => handleSelectUser(user)}
className='flex items-center justify-between gap-2'
>
<div className='flex items-center gap-2'>
<img
src={user.profile || '/placeholder.svg'}
alt={user.fullName}
className='h-8 w-8 rounded-full'
/>
<div className='flex flex-col'>
<span className='text-sm font-medium'>
{user.fullName}
</span>
<span className='text-xs text-zinc-400'>
{user.username}
</span>
</div>
</div>

{selectedUsers.find((u) => u.id === user.id) && (
<IconCheck className='h-4 w-4' />
)}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
<Button
variant={'default'}
onClick={onSubmit}
disabled={selectedUsers.length === 0}
>
Chat
</Button>
</div>
</DialogContent>
</Dialog>
)
}
4 changes: 4 additions & 0 deletions src/features/chats/data/chat-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { conversations } from './convo.json'

export type ChatUser = (typeof conversations)[number]
export type Convo = ChatUser['messages'][number]
Loading

0 comments on commit 93be363

Please sign in to comment.