Skip to content

Commit

Permalink
implement visual changes in app b00tc4mp#84
Browse files Browse the repository at this point in the history
  • Loading branch information
Eden23 committed Aug 27, 2024
1 parent b956ae3 commit 3cc5beb
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export default (req, res, next) => {

try {
logic.sendMessage(userId, chatId, content)
.then(() => res.status(201).json())
.catch(error => next(error))
} catch (error) {
next(error)
}
Expand Down
2 changes: 1 addition & 1 deletion staff/marti-herms/project/G-HUB/app/logic/sendMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default (chatId, content) => {
.then(response => {
const { status } = response

if (status === 200) return
if (status === 201) return

return response.json()
.then(body => {
Expand Down
32 changes: 28 additions & 4 deletions staff/marti-herms/project/G-HUB/app/src/home/Chat.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import { useParams } from 'react-router-dom'
import { IoIosSend as SendIcon } from 'react-icons/io'

Expand All @@ -19,15 +19,22 @@ import defaultAvatar from '../../images/defaultAvatar.svg'
import logic from '../../logic'

export default function Chat({ onOpenChat }) {
const [user, setUser] = useState(null)
const [users, setUsers] = useState([])
const [chat, setChat] = useState(null)
const [message, setMessage] = useState('')
const [messages, setMessages] = useState([])
const messageRef = useRef()
const { alert } = useContext()

const { sub: loggedInUser } = extractPayloadFromToken(sessionStorage.token)

const { userId } = useParams()

useEffect(() => {
messageRef.current?.scrollIntoView({ behaviour: 'smooth' })
}, [messages.length])

useEffect(() => {
try {
if (userId === loggedInUser) {
Expand All @@ -39,7 +46,12 @@ export default function Chat({ onOpenChat }) {
alert(error.message)
})
} else {
logic.openChat(userId)
logic.getUser(userId)
.then(user => {
setUser(user)

return logic.openChat(userId)
})
.then(chatId => setChat(chatId))
.catch(error => {
console.error(error)
Expand All @@ -66,6 +78,7 @@ export default function Chat({ onOpenChat }) {
if (intervalId) {
clearInterval(intervalId)
setChat(null)
setMessages([])
}
}
}, [chat])
Expand All @@ -77,11 +90,13 @@ export default function Chat({ onOpenChat }) {

const messageInput = form['message-input']

const message = messageInput.value
setMessage(messageInput.value)

try {
logic.sendMessage(chat, message)
.then(() => {
setMessage('')

loadMessages()
})
.catch(error => {
Expand All @@ -96,6 +111,10 @@ export default function Chat({ onOpenChat }) {
}
}

const handleInputChange = (e) => {
setMessage(e.target.value)
}

const loadMessages = () => {
try {
logic.getChatMessages(chat)
Expand All @@ -119,10 +138,15 @@ export default function Chat({ onOpenChat }) {
return <Container className='w-full h-full flex flex-col pb-[110px]' >
{userId !== loggedInUser ? <>
<Container className='w-full h-full flex flex-col'>
{user && <Container className='flex flex-row items-center ml-4 mt-4'>
<Avatar className='w-2/12 h-2/12' url={user.avatar || defaultAvatar} />
<Paragraph className='text-xl font-bold'>{user.username}</Paragraph>
</Container>}
{messages.map(message => <Message key={message.id} message={message} />)}
<div ref={messageRef} />
</Container>
<Form className='fixed w-full h-[50px] bottom-[60px] dark:bg-[#1e1e1e] flex flex-row justify-center items-center gap-2' onSubmit={handleSendMessage}>
<Input id='message-input' />
<Input id='message-input' value={message} onChange={handleInputChange} />
<Button className='bg-blue-800 rounded-full h-[40px] aspect-square' ><SendIcon className='w-8 h-8 ml-0.5 mt-1 text-white' /></Button>
</Form>
</> :
Expand Down
10 changes: 4 additions & 6 deletions staff/marti-herms/project/G-HUB/app/src/home/Game.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ export default function Game({ makeReviewVisibility, onCancel }) {
<Link className='text-white font-semibold text-lg text-center hover:text-violet-500 active:text-violet-500:' href={game.link}>Go to official page</Link>
</Container>
</>}

{makeReviewVisibility && <Form className='flex flex-row h-[15%] my-2 justify-start items-center box-content text-black' onSubmit={handleMakeReview}>
<Container className='flex flex-col mt-4' style={{ marginBottom: makeReviewVisibility ? '140px' : '60px' }}>
{reviews && reviews.map(review => <Review key={review.id} review={review} onDelete={handleDeleteReview} />)}
</Container>
{makeReviewVisibility && <Form className='fixed bottom-[60px] flex flex-row w-full h-auto p-1 dark:bg-[#1e1e1e] justify-start items-center box-content text-black' onSubmit={handleMakeReview}>
<Container className='flex flex-col justify-center items-center box-content w-[80%]'>
<Input name='comment' placeholder='comment' id='comment-input' />
<Container className='flex flex-row'>
Expand All @@ -163,9 +165,5 @@ export default function Game({ makeReviewVisibility, onCancel }) {
</Container>
<Button type='submit'><SendIcon className='w-10 h-10 dark:text-white' /></Button>
</Form>}

<Container className='flex flex-col mt-4 mb-10'>
{reviews && reviews.map(review => <Review key={review.id} review={review} onDelete={handleDeleteReview} />)}
</Container>
</>
}
16 changes: 11 additions & 5 deletions staff/marti-herms/project/G-HUB/app/src/home/GameBanner.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { IoRemoveCircleOutline as RemoveIcon } from 'react-icons/io5'
import { IoIosAddCircleOutline as AddIcon } from 'react-icons/io'
import { MdFavorite as FavIcon, MdFavoriteBorder as NotFavIcon } from "react-icons/md";


import Container from '../library/Container'
import Image from '../library/Image'
import Paragraph from '../library/Paragraph'
import Button from '../library/Button'

import useContext from '../context'

Expand Down Expand Up @@ -46,7 +52,7 @@ export default function GameBanner({ game, onInteraction, onGameClick, collectio
}

return <article className='flex flex-row items-center border-y border-solid border-slate-700 dark:bg-black'>
<button className='bg-transparent border-0' onClick={handleGameClick}>
<Button className='bg-transparent border-0' onClick={handleGameClick}>
<Container className='flex flex-col'>
<Container className='flex flex-row items-center'>
<Image className='w-2/12 h-2/12' src={game.image} />
Expand All @@ -56,10 +62,10 @@ export default function GameBanner({ game, onInteraction, onGameClick, collectio
<Paragraph>{game.description.length >= 25 ? game.description.slice(0, 25) + '...' : game.description}</Paragraph>
</Container>
</Container>
</button>
{collectionType !== 'devGames' && <Container className='flex flex-col gap-2 mr-2 h-full w-[90px]'>
<button className='bg-gray-500 rounded' onClick={handleAddGame}>{game.inLibrary ? 'Remove' : 'Add'}</button>
{game.inLibrary && <button className={game.inFavs ? 'bg-red-500 rounded' : 'bg-green-300 rounded'} onClick={handleFavGame}>Fav</button>}
</Button>
{collectionType !== 'devGames' && <Container className='flex flex-row gap-2 mr-2 h-full w-[90px]'>
<Button onClick={handleAddGame}>{game.inLibrary ? <RemoveIcon className='w-8 h-8 dark:text-white' /> : <AddIcon className='w-8 h-8 dark:text-white' />}</Button>
<Button onClick={handleFavGame} disabled={!game.inLibrary}>{game.inFavs ? <FavIcon className='w-8 h-8 text-red-600' /> : <NotFavIcon className='w-8 h-8 text-red-600' />}</Button>
</Container>}
</article>
}
13 changes: 7 additions & 6 deletions staff/marti-herms/project/G-HUB/app/src/home/Message.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import Container from '../library/Container'
import Paragraph from '../library/Paragraph'

import extractPayloadFromToken from '../../util/extractPayloadFromToken'
import formatTime from '../../util/formatTime'

export default function Message({ message }) {
const { sub: userId } = extractPayloadFromToken(sessionStorage.token)

return (message.author.id === userId) ?
<>
<Paragraph className='text-xs relative top-[25px] self-end mr-5 opacity-50'>{message.author.username}</Paragraph>
<Container className='max-w-[60%] min-w-[20%] h-auto p-1 rounded-full mt-3 mx-2 bg-blue-800 self-end' >
<Paragraph>{message.content}</Paragraph>
<Container className='max-w-[60%] min-w-[20%] h-auto p-3 rounded-3xl mt-2 mx-2 bg-blue-800 self-end flex flex-col justify-center items-end' >
<Paragraph className='text-lg text-wrap m-0'>{message.content}</Paragraph>
<time className='text-xs opacity-50 text-white mr-1'>{formatTime(new Date(message.date))}</time>
</Container>
</> :
<>
<Paragraph className='text-xs relative top-[25px] self-start ml-5 opacity-50'>{message.author.username}</Paragraph>
<Container className='max-w-[60%] min-w-[20%] h-auto p-1 rounded-full mt-3 mx-2 bg-green-700 self-start' >
<Paragraph>{message.content}</Paragraph>
<Container className='max-w-[60%] min-w-[20%] h-auto p-3 rounded-3xl mt-2 mx-2 bg-green-700 self-start flex flex-col justify-center items-start' >
<Paragraph className='text-lg text-wrap m-0'>{message.content}</Paragraph>
<time className='text-xs opacity-50 text-white ml-1'>{formatTime(new Date(message.date))}</time>
</Container>
</>
}
20 changes: 10 additions & 10 deletions staff/marti-herms/project/G-HUB/app/src/home/SearchResults.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import useContext from '../context'
import GameBanner from './GameBanner'
import UserBanner from './UserBanner'

export default function SearchResults({ onGameClick, onUserClick }) {
export default function SearchResults({ onGameClick, onUserClick, onChatClick }) {
const { alert } = useContext()

const [searchParams] = useSearchParams()
Expand All @@ -19,11 +19,14 @@ export default function SearchResults({ onGameClick, onUserClick }) {
const [debounceTimer, setDebounceTimer] = useState(null)

useEffect(() => {
if (q !== '' || q !== '@') {
debounceSearch()
} else {
clearTimeout(debounceTimer)
if (q === '@' || q === '') {
setResults([])
debounceTimer && clearTimeout(debounceTimer)
} else {
if (debounceTimer)
clearTimeout(debounceTimer)

debounceSearch()
}
}, [q])

Expand Down Expand Up @@ -60,20 +63,17 @@ export default function SearchResults({ onGameClick, onUserClick }) {
}

const debounceSearch = () => {
if (debounceTimer)
clearTimeout(debounceTimer)

setDebounceTimer(setTimeout(() => {
if (q.startsWith('@'))
loadUsers()
else
loadGames()
}, 1000))
}, 700))
}

return <section className='flex flex-col'>
{results.length > 0 && (q.startsWith('@') ?
results.map(user => <UserBanner key={user.id} user={user} onInteraction={loadUsers} onUserClick={onUserClick} />) :
results.map(user => <UserBanner key={user.id} user={user} onInteraction={loadUsers} onUserClick={onUserClick} onChatClick={onChatClick} />) :
results.map(game => <GameBanner key={game.id} game={game} onInteraction={loadGames} onGameClick={onGameClick} collectionType={'search'} />))}
</section>
}
11 changes: 9 additions & 2 deletions staff/marti-herms/project/G-HUB/app/src/home/UserBanner.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { RiUserFollowLine as FollowIcon, RiUserUnfollowLine as UnfollowIcon } from 'react-icons/ri'
import { IoIosSend as SendIcon } from 'react-icons/io'


import Container from '../library/Container'
import Avatar from '../library/Avatar'
Expand All @@ -12,7 +14,7 @@ import logic from '../../logic'
import defaultAvatar from '../../images/defaultAvatar.svg'
import extractPayloadFromToken from '../../util/extractPayloadFromToken'

export default function UserBanner({ user, onInteraction, onUserClick }) {
export default function UserBanner({ user, onInteraction, onUserClick, onChatClick }) {
const { alert } = useContext()

const { sub: currentUserId } = extractPayloadFromToken(sessionStorage.token)
Expand All @@ -37,6 +39,10 @@ export default function UserBanner({ user, onInteraction, onUserClick }) {
}
}

const handleOpenChat = () => {
onChatClick(user.id)
}

return <article className='flex flex-row w-full items-center justify-between p-3 border-y border-solid border-slate-700 dark:bg-black'>
<Button className='bg-transparent border-0' onClick={handleUserClick}>
<Container className='flex flex-col'>
Expand All @@ -46,8 +52,9 @@ export default function UserBanner({ user, onInteraction, onUserClick }) {
</Container>
</Container>
</Button>
{user.id !== currentUserId && <Container className='flex flex-col gap-2 mr-2 h-full'>
{user.id !== currentUserId && <Container className='flex flex-row gap-2 mr-2 h-full'>
<Button onClick={handleFollowUser}>{user.followed ? <UnfollowIcon className='w-8 h-8 dark:text-white' /> : <FollowIcon className='w-8 h-8 dark:text-white' />}</Button>
<Button className='h-[40px]' onClick={handleOpenChat} ><SendIcon className='w-8 h-8 ml-0.5 mt-1 text-white' /></Button>
</Container>}
</article>
}
8 changes: 4 additions & 4 deletions staff/marti-herms/project/G-HUB/app/src/home/UserList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import UserBanner from './UserBanner'

import logic from '../../logic'

export default function UserList({ onUserClick }) {
export default function UserList({ onUserClick, onChatClick }) {
const { alert } = useContext()

const location = useLocation()
Expand All @@ -20,7 +20,7 @@ export default function UserList({ onUserClick }) {
const [users, setUsers] = useState([])

useEffect(() => {
if (listType === 'following' || listType === 'chat')
if (listType === 'following')
loadFollowing()
else if (listType === 'followers')
loadFollowers()
Expand Down Expand Up @@ -59,7 +59,7 @@ export default function UserList({ onUserClick }) {
}

return <Container className='flex flex-col items-center w-full' >
<h2 className='dark:text-white font-bold underline underline-offset-4 my-2'>{listType.toUpperCase()}</h2>
{users.map(user => <UserBanner key={user.id} user={user} onInteraction={listType === 'following' ? loadFollowing : loadFollowers} onUserClick={onUserClick} />)}
<h2 className='dark:text-white font-bold mt-3 mb-2'>{listType.toUpperCase()}</h2>
{users.map(user => <UserBanner key={user.id} user={user} onInteraction={listType === 'following' ? loadFollowing : loadFollowers} onUserClick={onUserClick} onChatClick={onChatClick} />)}
</Container>
}
6 changes: 3 additions & 3 deletions staff/marti-herms/project/G-HUB/app/src/home/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ export default function Home({ onLogout }) {
<Routes>
<Route path={paths.home} element={<Library onGameClick={handleGame} />} />
<Route path={paths.profile + ':userId'} element={<Profile onChange={handleSearchUser} onGameClick={handleGame} />} />
<Route path={paths.following + ':userId'} element={<UserList onUserClick={handleSearchUser} />} />
<Route path={paths.followers + ':userId'} element={<UserList onUserClick={handleSearchUser} />} />
<Route path={paths.following + ':userId'} element={<UserList onUserClick={handleSearchUser} onChatClick={handleChat} />} />
<Route path={paths.followers + ':userId'} element={<UserList onUserClick={handleSearchUser} onChatClick={handleChat} />} />
<Route path={paths.addGame} element={<AddGame onAddGame={handleAddGame} />} />
<Route path={paths.search} element={<><Search /> <SearchResults onGameClick={handleGame} onUserClick={handleSearchUser} /></>} />
<Route path={paths.search} element={<><Search /> <SearchResults onGameClick={handleGame} onUserClick={handleSearchUser} onChatClick={handleChat} /></>} />
<Route path={paths.game + ':gameId'} element={<Game makeReviewVisibility={makeReviewVisibility} onCancel={handleCancelReview} />} />
<Route path={paths.chat + ':userId'} element={<Chat onOpenChat={handleChat} />} />
<Route path='/*' element={<NotFoundPage />} />
Expand Down
44 changes: 44 additions & 0 deletions staff/marti-herms/project/G-HUB/app/util/formatTime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
function formatTime(date) {
const seconds = Math.floor((Date.now() - date.getTime()) / 1000)

if (seconds < 60) {
return seconds + ' second' + (seconds === 1 ? '' : 's')
}

const minutes = Math.round(seconds / 60)

if (minutes < 60) {
return minutes + ' minute' + (minutes === 1 ? '' : 's')
}

const hours = Math.round(minutes / 60)

if (hours < 24) {
return hours + ' hour' + (hours === 1 ? '' : 's')
}

const days = Math.round(hours / 24)

if (days < 7) {
return days + ' day' + (days === 1 ? '' : 's')
}

const weeks = Math.round(days / 7)

if (weeks < 4) {
return weeks + ' week' + (weeks === 1 ? '' : 's')
}

const months = Math.round(weeks / 7)

if (months < 12) {
return months + ' month' + (months === 1 ? '' : 's')
}

const years = Math.round(months / 7)

return years + ' year' + (years === 1 ? '' : 's')

}

export default formatTime

0 comments on commit 3cc5beb

Please sign in to comment.