Skip to content

Commit

Permalink
Merge pull request #41 from Bayusetiawan45/feature-chat-onboarding
Browse files Browse the repository at this point in the history
Feature chat onboarding
  • Loading branch information
codebayu authored Jan 3, 2024
2 parents 9488789 + a990172 commit 1e4de2e
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 24 deletions.
30 changes: 30 additions & 0 deletions common/constant/drivers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,33 @@ export const tourTaskBoard: DriveStep[] = [
}
}
]

export const tourChatRoom: DriveStep[] = [
{
element: '#chat-card',
popover: {
title: 'Message',
description: 'The message will be shown here. Hover and click reply icon to reply to the message.',
side: 'bottom',
align: 'center'
}
},
{
element: '#google-sign-in',
popover: {
title: 'Sign In with Google',
description: 'You can sign in with your Google account to start sending messages.',
side: 'top',
align: 'center'
}
},
{
popover: {
title: "You're Ready to Get Started!",
description:
"Congratulations! You've now been introduced to all the awesome features of chat room. Happy Talking!",
side: 'top',
align: 'center'
}
}
]
13 changes: 9 additions & 4 deletions common/libs/drivers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import 'driver.js/dist/driver.css'

interface CreateDriversProps {
steps: DriveStep[]
product: string
timing?: number
}

export default function createDrivers({ steps }: CreateDriversProps) {
export default function createDrivers({ steps, product, timing = 1000 }: CreateDriversProps) {
let isProductTour = false
const driverObj = driver({
showProgress: true,
Expand All @@ -14,12 +16,15 @@ export default function createDrivers({ steps }: CreateDriversProps) {
})

if (typeof window !== 'undefined') {
isProductTour = !(window.localStorage.getItem('cb-product-tour') !== null)
isProductTour = !(window.localStorage.getItem(`cb-onboarding-${product}`) !== null)
}

function runDriver() {
driverObj?.drive()
window.localStorage.setItem('cb-product-tour', 'true')
const timeout = setTimeout(() => {
driverObj?.drive()
window.localStorage.setItem(`cb-onboarding-${product}`, 'true')
}, timing)
return () => clearTimeout(timeout)
}

return { runDriver, isProductTour }
Expand Down
6 changes: 2 additions & 4 deletions modules/board/components/TaskBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function TaskBoard() {
const hydrate = useHydrationZustand(useTaskBoard)
const mounted = useHasMounted()

const { runDriver, isProductTour } = createDrivers({ steps: tourTaskBoard })
const { runDriver, isProductTour } = createDrivers({ steps: tourTaskBoard, product: 'task-board' })

function onDragEnd(result: DropResult, columns: IColumns, setColumns: (columns: IColumns) => void) {
if (!result.destination) return // Jika Tidak ada kolom Tujuan
Expand Down Expand Up @@ -67,9 +67,7 @@ export default function TaskBoard() {
}

if (mounted && isProductTour) {
setTimeout(() => {
runDriver()
}, 1000)
runDriver()
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import { MdVerified as VerifiedIcon } from 'react-icons/md'
import Tooltip from '@/common/components/elements/Tooltip'
import { IMessage } from '@/common/types/messages'

interface IMessageCardProps extends IMessage {
interface IChatItemProps extends IMessage {
deleteMessage: (id: string) => void
sessionEmail: string
clickReply: (name: string) => void
}

export default function MessageCard({
export default function ChatItem({
id,
name,
message,
Expand All @@ -28,13 +28,18 @@ export default function MessageCard({
reply_to,
deleteMessage,
clickReply
}: IMessageCardProps) {
}: IChatItemProps) {
const [onHover, setOnHover] = useState(false)
const authorEmail = process.env.NEXT_PUBLIC_AUTHOR_EMAIL as string
const time = formatDistanceToNow(new Date(created_at), { addSuffix: true })

return (
<div className="flex items-start space-x-3">
<motion.div
id="chat-card"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="flex items-start space-x-3"
>
<Image src={image} alt={name} width={40} height={40} className="rounded-full" />
<div className="flex flex-col space-y-1">
<div className="flex items-center space-x-3">
Expand Down Expand Up @@ -83,6 +88,6 @@ export default function MessageCard({
<DeleteIcon size={15} className="text-red-500" />
</button>
)}
</div>
</motion.div>
)
}
21 changes: 21 additions & 0 deletions modules/chat/components/ChatItemSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react'

export default function ChatItemSkeleton() {
return (
<div id="chat-card" className="flex items-start space-x-3">
<div className="rounded-full w-11 h-11 bg-neutral-300 dark:bg-neutral-700 animate-pulse" />
<div className="flex flex-col space-y-1 w-[90%]">
<div className="flex items-center space-x-3">
<div className="flex space-x-1 items-center">
<span className="bg-neutral-300 dark:bg-neutral-700 animate-pulse h-3 w-36 rounded" />
</div>
<span className="bg-neutral-300 dark:bg-neutral-700 animate-pulse h-3 w-20 rounded" />
</div>

<div className="flex space-x-2">
<div className="font-sans bg-neutral-300 dark:bg-neutral-800 animate-pulse w-full h-14 rounded-xl rounded-tl-none" />
</div>
</div>
</div>
)
}
38 changes: 28 additions & 10 deletions modules/chat/components/ChatRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,30 @@ import { User } from 'next-auth'
import React, { useEffect, useRef, useState } from 'react'
import { v4 as uuid } from 'uuid'

import { tourChatRoom } from '@/common/constant/drivers'
import createDrivers from '@/common/libs/drivers'
import { firebase } from '@/common/libs/firebase'
import { IMessage, IRawMessages } from '@/common/types/messages'

import useHasMounted from '@/hooks/useHasMounted'

import ChatAuth from './ChatAuth'
import MessageCard from './MessageCard'
import ChatItem from './ChatItem'
import ChatItemSkeleton from './ChatItemSkeleton'

interface ChatRoomProps {
user: User
}

export default function ChatRoom({ user }: ChatRoomProps) {
const [messages, setMessages] = useState<IMessage[]>([])
const [loading, setLoading] = useState(true)
const [reply, setReply] = useState({ isReply: false, name: '' })
const [hasScrolledUp, setHasScrolledUp] = useState(false)
const chatListRef = useRef<HTMLDivElement | null>(null)
const mounted = useHasMounted()

const { runDriver, isProductTour } = createDrivers({ steps: tourChatRoom, product: 'chat-room', timing: 2000 })

const db = getDatabase(firebase)
const dbMessages = process.env.NEXT_PUBLIC_FIREBASE_DATABASE_CHAT
Expand Down Expand Up @@ -73,6 +82,7 @@ export default function ChatRoom({ user }: ChatRoomProps) {
return dateA.getTime() - dateB.getTime()
})
setMessages(transformMessages)
setLoading(false)
})
}, [db, dbMessages])

Expand Down Expand Up @@ -105,21 +115,29 @@ export default function ChatRoom({ user }: ChatRoomProps) {
}
}, [])

if (mounted && isProductTour) {
runDriver()
}

return (
<div>
<div
ref={chatListRef}
className="h-[60vh] scroll-smooth md:h-[65vh] no-scrollbar overflow-y-auto border-b border-neutral-200 dark:border-neutral-700 pb-2 mb-4 space-y-6"
>
{messages?.map(message => (
<MessageCard
key={message.id}
{...message}
sessionEmail={String(user?.email)}
deleteMessage={deleteMessage}
clickReply={clickReply}
/>
))}
{loading ? (
<ChatItemSkeleton />
) : (
messages?.map(message => (
<ChatItem
key={message.id}
{...message}
sessionEmail={String(user?.email)}
deleteMessage={deleteMessage}
clickReply={clickReply}
/>
))
)}
</div>
<ChatAuth user={user} sendMessage={sendMessage} reply={reply} cancleReply={cancleReply} />
</div>
Expand Down
1 change: 1 addition & 0 deletions modules/chat/components/SignInGoogleButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FcGoogle as GoogleIcon } from 'react-icons/fc'
export default function SignInGoogleButton() {
return (
<button
id="google-sign-in"
onClick={() => signIn('google')}
className="flex space-x-2 p-2 rounded-lg items-center justify-center shadow-sm border dark:border-neutral-700 hover:scale-[101%] transition duration-300 bg-white dark:bg-neutral-700 w-full mt-2 mb-2"
data-umami-event="Sign In to Chat: Google"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "v2.codebayu.com",
"version": "1.2.1",
"version": "1.2.2",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down

0 comments on commit 1e4de2e

Please sign in to comment.