Skip to content

Instantly share code, notes, and snippets.

@Daltonic
Created June 23, 2023 20:56
Show Gist options
  • Save Daltonic/80196de5b0f62a3066ab18625ea7d5a6 to your computer and use it in GitHub Desktop.
Save Daltonic/80196de5b0f62a3066ab18625ea7d5a6 to your computer and use it in GitHub Desktop.
Dapp Cinemas
import { Menu } from '@headlessui/react'
import { FiEdit } from 'react-icons/fi'
import { BiLogInCircle } from 'react-icons/bi'
import { SiGnuprivacyguard } from 'react-icons/si'
import { BsChatLeftDots } from 'react-icons/bs'
import { FiChevronDown } from 'react-icons/fi'
import { MdOutlineJoinLeft } from 'react-icons/md'
import { toast } from 'react-toastify'
import {
createNewGroup,
joinGroup,
loginWithCometChat,
signUpWithCometChat,
} from '../services/chat'
import { setGlobalState, useGlobalState } from '../store'
const ChatActions = ({ movie, group }) => {
const [connectedAccount] = useGlobalState('connectedAccount')
const [owner] = useGlobalState('deployer')
const [currentUser] = useGlobalState('currentUser')
const handleSignUp = async () => {
await toast.promise(
new Promise(async (resolve, reject) => {
await signUpWithCometChat(connectedAccount)
.then((user) => resolve(user))
.catch((error) => {
alert(JSON.stringify(error))
reject(error)
})
}),
{
pending: 'Signning up...',
success: 'Signed up successfully, please login 👌',
error: 'Encountered error 🤯',
}
)
}
const handleLogin = async () => {
await toast.promise(
new Promise(async (resolve, reject) => {
await loginWithCometChat(connectedAccount)
.then((user) => {
setGlobalState('currentUser', user)
resolve(user)
window.location.reload()
})
.catch((error) => {
alert(JSON.stringify(error))
reject(error)
})
}),
{
pending: 'Logging...',
success: 'Logged in successfully 👌',
error: 'Encountered error 🤯',
}
)
}
const handleCreateGroup = async () => {
await toast.promise(
new Promise(async (resolve, reject) => {
await createNewGroup(`guid_${movie.id}`, movie.name)
.then((group) => {
setGlobalState('group', group)
resolve(group)
window.location.reload()
})
.catch((error) => {
alert(JSON.stringify(error))
reject(error)
})
}),
{
pending: 'Creating group...',
success: 'Group created successfully 👌',
error: 'Encountered error 🤯',
}
)
}
const handleJoinGroup = async () => {
await toast.promise(
new Promise(async (resolve, reject) => {
await joinGroup(`guid_${movie.id}`)
.then((group) => {
setGlobalState('group', group)
resolve()
window.location.reload()
})
.catch((error) => {
alert(JSON.stringify(error))
reject(error)
})
}),
{
pending: 'Joining group...',
success: 'Group joined successfully 👌',
error: 'Encountered error 🤯',
}
)
}
return (
<Menu as="div" className="relative inline-block text-left mx-auto">
<Menu.Button
className="inline-flex justify-center items-center space-x-2
rounded-md bg-black bg-opacity-10 px-4 py-2 text-sm
font-medium text-black hover:bg-opacity-30 focus:outline-none
focus-visible:ring-2 focus-visible:ring-white
focus-visible:ring-opacity-75"
>
<span>Chat Options</span>
<FiChevronDown size={17} />
</Menu.Button>
<Menu.Items
className="absolute right-0 mt-2 w-56 origin-top-right
divide-y divide-gray-100 rounded-md bg-white shadow-md
ing-1 ring-black ring-opacity-5 focus:outline-none"
>
{!currentUser && (
<>
<Menu.Item>
{({ active }) => (
<button
className={`flex justify-start items-center space-x-1 ${
active ? 'bg-gray-200 text-black' : 'text-red-500'
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
onClick={handleSignUp}
>
<SiGnuprivacyguard size={17} />
<span>Chat SignUp</span>
</button>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<button
className={`flex justify-start items-center space-x-1 ${
active ? 'bg-gray-200 text-black' : 'text-gray-900'
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
onClick={handleLogin}
>
<BiLogInCircle size={17} />
<span>Chat Login</span>
</button>
)}
</Menu.Item>
</>
)}
{currentUser && (
<>
{currentUser.uid != owner && group && !group.hasJoined && (
<Menu.Item>
{({ active }) => (
<button
className={`flex justify-start items-center space-x-1 ${
active ? 'bg-gray-200 text-black' : 'text-gray-900'
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
onClick={handleJoinGroup}
>
<MdOutlineJoinLeft size={17} />
<span>Join Group</span>
</button>
)}
</Menu.Item>
)}
{currentUser.uid == owner && !group && (
<Menu.Item>
{({ active }) => (
<button
className={`flex justify-start items-center space-x-1 ${
active ? 'bg-gray-200 text-black' : 'text-gray-900'
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
onClick={handleCreateGroup}
>
<FiEdit size={17} />
<span>Create Group</span>
</button>
)}
</Menu.Item>
)}
{group && group.hasJoined && (
<Menu.Item>
{({ active }) => (
<button
className={`flex justify-start items-center space-x-1 ${
active ? 'bg-gray-200 text-black' : 'text-gray-900'
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
onClick={() => setGlobalState('chatModal', 'scale-100')}
>
<BsChatLeftDots size={17} />
<span>Chat</span>
</button>
)}
</Menu.Item>
)}
</>
)}
</Menu.Items>
</Menu>
)
}
export default ChatActions
import { FaTimes } from 'react-icons/fa'
import { setGlobalState, useGlobalState } from '../store'
import Identicon from 'react-identicons'
import { truncate } from '../store'
import { getMessages, sendMessage, listenForMessage } from '../services/chat'
import { useState, useEffect } from 'react'
const ChatModal = ({ movie }) => {
const [chatModal] = useGlobalState('chatModal')
const [message, setMessage] = useState('')
const [messages] = useGlobalState('messages')
const onSendMessage = async (e) => {
e.preventDefault()
if (!message) return
await sendMessage('guid_' + movie.id, message).then((msg) => {
setGlobalState('messages', (prevState) => [...prevState, msg])
setMessage('')
scrollToEnd()
})
}
useEffect(() => {
const fetchData = async () => {
await getMessages('guid_' + movie.id).then((msgs) => {
setGlobalState('messages', msgs)
scrollToEnd()
})
await listenForMessage('guid_' + movie.id).then((msg) => {
setGlobalState('messages', (prevState) => [...prevState, msg])
scrollToEnd()
})
}
fetchData()
}, [])
const scrollToEnd = () => {
const elmnt = document.getElementById('messages-container')
elmnt.scrollTop = elmnt.scrollHeight
}
return (
<div
className={`fixed -top-4 left-0 w-screen h-screen flex items-center justify-center bg-black bg-opacity-50 transform z-50 transition-transform duration-300 ${chatModal}`}
>
<div className="bg-slate-200 shadow-lg shadow-slate-900 rounded-xl w-11/12 md:w-3/5 h-[30rem] p-6 relative">
<div className="flex justify-between items-center">
<h2 className="capitalize">{movie.name}: Chat Room</h2>
<FaTimes
className="cursor-pointer"
onClick={() => setGlobalState('chatModal', 'scale-0')}
/>
</div>
<div
id="messages-container"
className="overflow-y-scroll overflow-x-hidden h-[20rem] scroll-bar mt-5 px-4 py-3 bg-gray-300 rounded-md"
>
<div className="w-11/12">
{messages.map((msg, i) => (
<Message message={msg.text} uid={msg.sender.uid} key={i} />
))}
</div>
</div>
<form className="h-[4rem] w-full mt-4" onSubmit={onSendMessage}>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
className="h-full w-full p-5 focus:outline-none focus:ring-0 rounded-md border-none
bg-[rgba(0,0,0,0.7)] text-white placeholder-white"
placeholder="Leave a message..."
/>
</form>
</div>
</div>
)
}
const Message = ({ message, uid }) => {
return (
<div className="flex justify-start items-center space-x-3 space-y-3">
<div className="flex items-center space-x-2">
<Identicon string={uid} size={15} className="rounded-full" />
<p className="font-semibold text-sm">{truncate(uid, 4, 4, 11)}</p>
</div>
<p className="text-xs">{message}</p>
</div>
)
}
export default ChatModal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment