can someone tell me why in the world the drawCard() function runs 4 times as it should and then 52 more times the deck is 52 items long it must be related
but this
const initCard = ()=>{return deck.map((card,index)=>{return index<4 && drawCard(index%2===0?'player':'dealer')})}
so I don't know why does it happen
here is the full component
import Box from '#mui/material/Box';
import { useEffect, useRef, useState } from 'react';
import Card from '../components/Card'
import {styles} from '../visuals/Styles'
import { drawCardAnimation } from '../visuals/Animations'
function Gamepage() {
const [deck, setDeck] = useState([]);
/*let dealerHand=[];
let playerHand=[];*/
const [dealerHand, setDealerHand] = useState([]);
const [playerHand, setPlayerHand] = useState([]);
const [screenState, setScreenState] = useState('placeBet')
const first = useRef(true) //in order to prevent the effect of react strict we use ref to keep alive the first var which tells us if the useEffect hasnt been executed yes
useEffect(()=>
{
if(first.current){
first.current =false;
getDeck();
}
},[]);
const getDeck = async () =>{
const res = await fetch('http://localhost:5000/deck/shuffled');
const data = await res.json();
setDeck(data);
}
const initCard = ()=>{return deck.map((card,index)=>{return index<4 && drawCard(index%2===0?'player':'dealer')})}
const countCards = (hand)=>{
let res=0;
return {"cardsCount":hand.map(({suit,number,imgPath})=>{ return number }).sort((a, b) => b-a).map((value)=>{
if(value ===1 && res+11 <= 21)
res +=11;
else
res+=value;
return res
})[hand.length-1], "isBusted": res<=21 ? false:true};
}
const isBlackJack = (hand)=>{
return hand.length === 2 && countCards(hand).cardsCount === 21
}
const isPlayerWon= ()=>{
isBlackJack(playerHand) && console.log("BLACK JACK !");
return isBlackJack(playerHand) || (!countCards(playerHand).isBusted && countCards(dealerHand).isBusted) || (countCards(playerHand).cardsCount>=countCards(dealerHand).cardsCount && !countCards(playerHand).isBusted)
}
const drawToDealer = ()=>{
while(countCards(dealerHand).cardsCount<17){
drawCard('dealer')}
}
const drawCard = (target) =>
{
console.log("drawn");
let index = dealerHand.length + playerHand.length;
if(deck[index]&& target==='dealer' && !dealerHand.includes(deck[index]))
{
//dealerHand.push(deck[index])
setDealerHand((prev)=>[...prev, deck[index]])
}
else if(deck[index]&& target==='player'&& !playerHand.includes(deck[index]))
{
//playerHand.push(deck[index]);
setPlayerHand((prev)=>[...prev, deck[index]])
}
return deck[index]&&
<Card
key={index}
stl={index===1?styles.firstDealerCard:styles.card}
cardImg={( target==='dealer'&&dealerHand.length===1)?'upsidedownCard':deck[index].imgPath}
animation={drawCardAnimation(target==='dealer'?dealerHand.length-1:playerHand.length-1,target)}/>;
}
return (
<div>
<Box sx={styles.box}>
{/*TODO find out why functions inside onClick does not work
and make the end game prompt on screen
*/}
<Card stl={styles.deck} cardImg={'upsidedownCard'} />
{
(screenState==='placeBet')?
<img src={require('../assets/btnPlaceBet.png')} alt='' style={styles.btnPlaceBet} onClick={()=>setScreenState('gameStart')} />
:initCard()
}
{
screenState==='gameStart' && <img src={require('../assets/btnHit.png')} alt='' style={styles.btnHit} onClick={()=>{ drawCard('player'); console.log(playerHand);}} />
}
{
screenState==='gameStart' && <img src={require('../assets/btnStand.png')} alt='' style={styles.btnStand} onClick={()=>{ setScreenState('dilearsTurn')}} />
}
{
screenState==='gameStart' && <img src={require('../assets/btnDouble.png')} alt='' style={styles.btnDouble} onClick={()=>{ console.log('money is doubled'); drawCard('player'); /*console.log(playerHand);*/;setScreenState('dilearsTurn')}} />
}
{
screenState==='dilearsTurn' && <Card stl={styles.revealedCard} cardImg={dealerHand[0].imgPath} />
}
{
screenState==='dilearsTurn' && drawToDealer()
}
{
screenState==='dilearsTurn' && console.log(dealerHand.length)
}
{
screenState==='dilearsTurn' &&console.log(isPlayerWon() ?
`player wins ${countCards(playerHand).cardsCount} and dealer ${countCards(dealerHand).cardsCount} ${countCards(dealerHand).isBusted ? 'dealer busted':''}`
:
`dealer wins ${countCards(dealerHand).cardsCount} and player ${countCards(playerHand).cardsCount} ${countCards(playerHand).isBusted ? 'player busted':''}`)
}
{screenState==='dilearsTurn' && setTimeout(()=>{
console.log('game ended');
setTimeout(()=>{
setScreenState('placeBet')
},2000);
},3000)}
</Box>
</div>
)
}
export default Gamepage
Related
I am fetching data from the Backend and loading them in the card using react-tinder-card
Swiping works properly but unable to swipe using the buttons
I follow the documentation but still did not work
Here is the sample
Swiping gestures are working fine.
But when implement by checking documentation things did not work
Things are not working and tomorrow is my project day
import React, { useEffect, useState, useContext, useRef } from "react";
function Wink() {
const [people, setPeople] = useState([]);
const [loading, setLoading] = useState(false);
const [currentIndex, setCurrentIndex] = useState(people.length - 1)
const [lastDirection, setLastDirection] = useState()
// used for outOfFrame closure
const currentIndexRef = useRef(currentIndex)
const childRefs = useMemo(
() =>
Array(people.length)
.fill(0)
.map((i) => React.createRef()),
[]
)
const updateCurrentIndex = (val) => {
setCurrentIndex(val)
currentIndexRef.current = val
}
const canGoBack = currentIndex < people.length - 1
const canSwipe = currentIndex >= 0
// set last direction and decrease current index
const swiped = (direction, nameToDelete, index) => {
setLastDirection(direction)
updateCurrentIndex(index - 1)
}
const outOfFrame = (name, idx) => {
console.log(`${name} (${idx}) left the screen!`, currentIndexRef.current)
// handle the case in which go back is pressed before card goes outOfFrame
currentIndexRef.current >= idx && childRefs[idx].current.restoreCard()
// TODO: when quickly swipe and restore multiple times the same card,
// it happens multiple outOfFrame events are queued and the card disappear
// during latest swipes. Only the last outOfFrame event should be considered valid
}
const swipe = async (dir) => {
if (canSwipe && currentIndex < db.length) {
await childRefs[currentIndex].current.swipe(dir) // Swipe the card!
}
}
// increase current index and show card
const goBack = async () => {
if (!canGoBack) return
const newIndex = currentIndex + 1
updateCurrentIndex(newIndex)
await childRefs[newIndex].current.restoreCard()
}
useEffect(() => {
setLoading(true);
axios
.post("http://localhost:4000/api/all-profile", { email })
.then(function (response) {
setPeople(response.data);
setCurrentIndex(response.data.length);
}
}, []);
return (
<div className="DateMainDiv">
<Header />
<div className="ProfieCards">
{people.map((person) => (
<TinderCard
className="swipe"
key={person.email}
ref={childRefs[index]}
preventSwipe={swipe}
onSwipe={(dir) => swiped(dir, person.name, person.email)}
onCardLeftScreen={onCardLeftScreen}
onCardUpScreen={onCardUpScreen}
>
<div
style={{ backgroundImage: `url(${person.image})` }}
className="Winkcard"
>
<img
onLoad={handleLoad}
src={person.image}
alt="Image"
className="TinderImage"
/>
<h3>
{person.name}{" "}
<IconButton
style={{ color: "#fbab7e" }}
onClick={() => handleOpen(person.email)}
>
<PersonPinSharpIcon fontSize="large" />
{parseInt(person.dist/1000)+"KM Away"}
</IconButton>
</h3>
</div>
</TinderCard>
))}
<SwipeButtonsLeft onClick={()=>{swipe("left")}} />
<SwipeButtonsLeft onClick={()=>{goback()}} />
<SwipeButtonsLeft onClick={()=>{swipe("right")}} />
</div>
</div>
);
}
export default Wink;
I'm new to React and trying to add some audio to a tenzies game.
The audio is getting weirder every time I click the roll button. And after clicking for a while, the sound is fading away. There is also a warning in the console: 'The AudioContext was not allowed to start.'
I can't find out what causing this issue. Please help!
I don't know how to run react code in StackOverflow. So I'm adding a link to the github repository and live site URL of this game.
Here is the full App.js component's code:
import React from 'react';
import Die from './Components/Die';
import { nanoid } from 'nanoid';
import Confetti from 'react-confetti';
import {Howl} from 'howler';
import winSound from './audio/win.mp3';
import rollSound from './audio/roll.mp3';
import holdSound from './audio/hold.mp3';
export default function App(){
const [dice, setDice] = React.useState(generateNewDice());
const [tenzies, setTenzies] = React.useState(false);
const [audio, setAudio] = React.useState(true);
const [rollCount, setRollCount] = React.useState(0);
const [timer, setTimer] = React.useState(0);
const [timerRunning, setTimerRunning] = React.useState(false);
function holdDieObject(){
return {
value: Math.floor(Math.random()*6) + 1,
isHeld: false,
id: nanoid()
}
}
function generateNewDice(){
let newDice= [];
for(let i=0; i<10; i++){
newDice.push(holdDieObject());
}
return newDice;
}
React.useEffect(()=>{ //Count time per 10 milliseconds when timer is running
let interval;
if(timerRunning){
interval = setInterval(() => {
setTimer((prevTime) => prevTime + 10)
}, 10)
}else{
clearInterval(interval);
}
return () => clearInterval(interval);
},[timerRunning])
React.useEffect(()=>{ //Check all the dice are matched or not
const someDiceHeld = dice.some(die => die.isHeld);
const allDiceHeld = dice.every(die => die.isHeld);
const firstDiceValue = dice[0].value;
const allSameValue = dice.every(die=> die.value === firstDiceValue);
if(someDiceHeld){
setTimerRunning(true);
}
if(allDiceHeld && allSameValue){
setTenzies(true);
// audio && victorySound.play(); // This brings up dependency warning. So moved it to the bottom
setTimerRunning(false)
}
},[dice])
const victorySound = new Howl({
src: [winSound]
})
if(tenzies){
audio && victorySound.play(); // Here
}
const rollDieSound = new Howl({
src: [rollSound]
})
const holdDieSound = new Howl({
src: [holdSound]
})
function holdDice(id){
audio && holdDieSound.play();
setDice(oldDice => oldDice.map(die =>{
return die.id===id ?
{
...die,
isHeld: !die.isHeld
} :
die;
}))
}
function rollDice(){
if(!tenzies){
setDice(oldDice => oldDice.map(die=>{
audio && rollDieSound.play();
return die.isHeld ? die : holdDieObject();
}))
setRollCount(prevCount => prevCount + 1);
}else{
setTenzies(false);
setDice(generateNewDice());
setRollCount(0);
setTimer(0);
}
}
function toggleMute(){
setAudio(prevState => !prevState);
}
function startNewGame(){
setTenzies(false);
setDice(generateNewDice());
}
const minutes = <span>{("0" + Math.floor((timer / 60000) % 60)).slice(-2)}</span>
const seconds = <span>{("0" + Math.floor((timer / 1000) % 60)).slice(-2)}</span>
const milliseconds = <span>{("0" + ((timer / 10) % 100)).slice(-2)}</span>
const dieElements = dice.map((die) => {
return <Die key={die.id}
value={die.value}
isHeld={die.isHeld}
holdDice={()=> holdDice(die.id)}
/>
})
return(
<div>
<main className="board">
<button onClick={toggleMute} className="mute-btn">{audio ? "🔉" : "🔇"}</button>
<h1>Tenzies</h1>
<p>Roll untill the dice are the same. Click each die to freeze it at its current value between rolls.</p>
<div className="die-container">
{dieElements}
</div>
<button onClick={rollDice}>Roll</button>
{tenzies && <div className="scoreboard">
<h2>Congratulations!</h2>
<p className='rollCount'>Rolled: {rollCount}</p>
<p className="rolltime">Time Taken: {minutes}:{seconds}:{milliseconds}</p>
<h3>Your Score: 4500</h3>
<button className='close' onClick={startNewGame}>New Game</button>
</div>}
</main>
{tenzies && <Confetti className="confetti" recycle={false} />}
</div>
)
}
I am making a mern ecommerce website i just want to see how useEffect works so i console.log in some part of useEffect and loadFilteredResults i saw that --->
initial
entry
skip
entry1
screen shot
but i think it shoud be-->
initial
entry
entry1
skip
why console give this?? i am a begginer, i am a self learner , so please if you need any extra info please comment.
code snippet-->
const loadFilteredResults = (newFilters) => {
console.log("entry")
getFilteredProducts(skip, limit, newFilters).then((data) => {
console.log("entry1")
if (data.error) {
setError(data.error);
} else {
//console.log(data);
setFilteredResults(data.data);
//console.log("size-->");
//console.log(data.size);
setSize(data.size);
setSkip(0);
}
});
};
....
....
useEffect(() => {
init();
console.log("initial");
loadFilteredResults(skip, limit, myFilters.filters);
console.log("skip");
}, []);
//full code of shop.js
import React, { useEffect, useState } from "react";
import Layout from "./Layout";
import Card from "./Card";
import { getCategories, getFilteredProducts } from "./apiCore";
import Checkbox from "./Checkbox";
import RadioBox from "./RadioBox";
import { prices } from "./fixedPrices";
const Shop = () => {
const [myFilters, setMyFilters] = useState({
filters: { category: [], price: [] }
});
const [categories, setCategories] = useState([]);
const [error, setError] = useState(false);
const [limit, setLimit] = useState(3);//prpduct lesss so use 3 but sir used 6
const [skip, setSkip] = useState(0);
const [size, setSize] = useState(0);
const [filteredResults, setFilteredResults] = useState([]);
const init = () => {
getCategories().then((data) => {
if (data.error) {
//console.log("error");
setError(data.error);
} else {
//console.log("set");
//console.log(data);
setCategories(data);
//console.log(data);
}
});
};
const loadFilteredResults = (newFilters) => {
//console.log(newFilters);
console.log("entry")
getFilteredProducts(skip, limit, newFilters).then((data) => {
console.log("entry1")
if (data.error) {
setError(data.error);
} else {
//console.log(data);
setFilteredResults(data.data);
//console.log("size-->");
//console.log(data.size);
setSize(data.size);
setSkip(0);
}
});
};
const loadMore = () => {
console.log("skip"+skip);
console.log("limit"+limit);
let toSkip = skip + limit;
console.log("toSkip"+toSkip);
getFilteredProducts(toSkip, limit, myFilters.filters).then((data) => {
//console.log("filter");
//console.log( myFilters.filters)
if (data.error) {
setError(data.error);
} else {
//console.log(filteredResults);
//console.log(data.data);
setFilteredResults([...filteredResults, ...data.data]);
//console.log("after");
//console.log(...filteredResults);
//console.log(filteredResults);
//console.log(filteredResults);
//console.log([...filteredResults])
//console.log([...filteredResults, ...data.data])
setSize(data.size);
setSkip(toSkip);
}
});
};
const loadMoreButton = () => {
return (
size > 0 &&
size >= limit && (
<button onClick={loadMore} className="btn btn-warning mb-5">
load more
</button>
)
);
};
useEffect(() => {
init();
//console.log(skip);
console.log("initial");
loadFilteredResults(skip, limit, myFilters.filters);
console.log("skip");
}, []);
const handleFilters = (filters, filterBy) => {
//console.log("SHOP", filters, filterBy);
const newFilters = { ...myFilters };
//console.log(newFilters);
newFilters.filters[filterBy] = filters;
//console.log(typeof(filters));
if (filterBy === "price") {
let priceValues = handlePrice(filters);
newFilters.filters[filterBy] = priceValues;
//console.log(priceValues);
}
//console.log(myFilters.filters);
loadFilteredResults(myFilters.filters);
setMyFilters(newFilters);
};
const handlePrice = (value) => {
const data = prices;
let array = [];
//console.log(value);
for (let key in data) {
if (data[key]._id === parseInt(value)) {
array = data[key].array;
}
}
return array;
};
// const x = (filters)=>{
// console.log("filters:"+filters);
// handleFilters(filters, "category")
// }
return (
<Layout
title="Shop Page"
description="search and buy books of your choice"
className="container-fluid"
>
<div className="row">
<div className="col-4">
<h4>Filter by categories</h4>
<ul>
{/* below will be show in list show we wrap it in unorder list */}
<Checkbox
categories={categories}
handleFilters={(filters) =>
handleFilters(filters, "category")
}
/>
</ul>
<h4>Filter by price range</h4>
<div>
<RadioBox
prices={prices}
handleFilters={(filters) => handleFilters(filters, "price")}
/>
</div>
</div>
<div className="col-8">
<h2 className="mb-4">Products</h2>
<div className="row">
{filteredResults.map((product, i) => (
<Card key={i} product={product} />
))}
</div>
<hr />
{loadMoreButton()}
</div>
</div>
</Layout>
);
};
export default Shop;
getFilteredProducts must be a Promise. Please read Using promises
Callbacks added with then() will never be invoked before the
completion of the current run of the JavaScript event loop.
I am trying to make a Sudoku solver. I have a parent component Board and a child component Possible which shows available options for any box in the board. I passed the state of board,selected(selected box position in the board) and function to update board as props. But when I try to change board from Possible it doesn't change unless the selected box selected is changed from parent component. I am trying to change board element from child component.
Here is my Board component.
import React, { useState } from 'react';
import Possibles from './avails.jsx';
import solve, { initBoard } from '../help';
function Board() {
const [msg, setmsg] = useState('');
const [solved, setSolved] = useState(false);
const [grid, setGrid] = useState(initBoard());
const [selected, setSelected] = useState([0, 0]);
const solveBoard = () => {
const solution = solve(grid);
setGrid(solution);
setSolved(true);
let a = true;
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
// console.log(i,j)
if (grid[i][j] === 0) {
// console.log(grid[i][j]);
a = false;
}
}
}
if (!a) {
setmsg('Invalid Board!');
} else setmsg('Here is your solution!');
};
const updatePosition = (row, col) => {
setSelected([row, col]);
};
const resetBoard = () => {
setGrid(initBoard());
setSolved(!solved);
setmsg('');
};
return (
<div className="board">
Sudoku Solver
{grid.map((row, index) => (
<div key={index} className="row">
{row.map((el, i) => (
<button
type="button"
key={i}
className={selected[0] === index && selected[1] === i ? 'el selected' : 'el'}
onClick={() => { updatePosition(index, i); }}
>
{el === 0 ? '' : el}
</button>
))}
</div>
))}
{setSolved
? <Possibles board={grid} pos={selected} setGrid={setGrid} setPos = {setSelected}/> : ''}
<button type="button" className="btn" onClick={solveBoard}>Solve</button>
<button type="button" className="btn" onClick={resetBoard}>Reset</button>
<div>{msg}</div>
</div>
);
}
export default Board;
And here is my child component Possibles.
import React, { useState, useEffect } from 'react';
import { getAvailableNumbers } from '../help';
function Possibles({ board, pos, setGrid }) {
const [possibles, setPosibles] = useState([]);
useEffect(() => {
const avails = getAvailableNumbers(board, pos);
avails.unshift(0);
setPosibles(avails, board, possibles);
}, [pos,board]);
const updateGrid = (opt) => {
// setPosibles((prev) => prev.filter((x) => x !== opt || x === 0));
board[pos[0]][pos[1]] = opt;
setGrid(board);
};
return (
<div>
{possibles.map((opt) => (
<button type="button" key={opt} onClick={() => { updateGrid(opt); }}>{opt === 0 ? 'X' : opt}</button>
))}
</div>
);
}
export default Possibles;
please change your 'updateGrid' function to -
const updateGrid = (opt) => {
// setPosibles((prev) => prev.filter((x) => x !== opt || x === 0));
board[pos[0]][pos[1]] = opt;
board = [...board]; // this will make parent component rerender
setGrid(board);
};
input to setPosibles should be an array according to first line of 'Possibles' component -
setPosibles(avails, board, possibles);
Edit - react basically uses shallow comparison for props, state to detect new available change. By using a spread operator we are a creating new array with a new memory location, this let react know about new change and rerendering is triggered.
My redux store updates perfectly
after sorting
before sorting
But the props in my component don't update even when the store has updated and so the child components still show the old values. I'm sorting my channels according to the timestamp. The sorting function updates the redux store but it still renders the non-sorted data.
the output it should be sorted but it remains the same(unsorted)
This is my component code
export const RoomItem = (props) => {
const [roomLiveStatus, setRoomLiveStatus] = useState(false);
const compareTimestamp = (t1 = 0, t2 = 0) => {
return (t1.lastMessage && t2.lastMessage) && t2.lastMessage.timestamp - t1.lastMessage.timestamp
}
const getRoomData = () => {
const { roomData, workspace } = props;
const { workspaceId } = workspace
const workspaceIdLowerCase = workspaceId.toLowerCase()
const { roomId } = roomData;
const roomIdLowerCase = roomId.toLowerCase()
firebase
.firestore()
.collection(`sessions/${workspaceIdLowerCase}/rooms`)
.doc(`${roomIdLowerCase}`)
.onSnapshot(doc => {
if (doc.exists) {
// console.log("LIVE Sessions doc: ", doc.data())
const { currentSession } = doc.data()
if (currentSession !== "") {
setRoomLiveStatus(true)
} else {
setRoomLiveStatus(false)
}
}
})
}
useEffect(() => {
getRoomData();
},[])
useEffect(() => {
// do something
getRoomData();
// console.log(props,"props of roomitem")
},[props.sortType])
const strip = (value) => {
const { user, content } = value
let name = user.name;
let firstName = name.trim().split(" ")[0]
if (value.type === 0) {
if ( (firstName.length + content.length) > 32 ) {
let completeContent = `${firstName}: ${content}`
return `${completeContent.slice(0, 32)}...`
} else {
return `${firstName}: ${content}`
}
} else if (value.type === 1) {
return <span>{firstName}: <FontAwesomeIcon icon={faCalendarAlt} className="text-theme" /> Schedule</span>
} else if (value.type === 2) {
return (
<span>{firstName}: <FontAwesomeIcon icon={faClipboard} className="text-theme" />Files</span>
);
} else if (value.type === 3) {
return <span>{firstName}: <FontAwesomeIcon icon={faPoll} className="text-theme" /> Poll</span>
} else if (value.type === 4) {
return <span>{firstName}: <FontAwesomeIcon icon={faTasks} className="text-theme" /> Quiz</span>
} else if (value.type === 6) {
if ( (firstName.length + content.length) > 32) {
let len = 32 - firstName.length;
return <span>{firstName}: <FontAwesomeIcon icon={faImage} /> {content.length > len ? content.slice(0, len) + '…' : content}</span>
} else {
return <span>{firstName}: <FontAwesomeIcon icon={faImage} /> Photo</span>
}
} else if (value.type === 7) {
if ( (firstName.length + content.length) > 32) {
let len = 32 - firstName.length;
return <span>{firstName}: <FileIcon message={value} /> {content.length > len ? content.slice(0, len) + '…' : content}</span>
} else {
return <span>{firstName}: <FileIcon message={value} /> {value.metaData && value.metaData.name}</span>
}
} else if (value.type === 8) {
return <span>{content.length > 36 ? `${content.slice(0, 36)}...` : content}</span>
} else if (value.type === 9) {
return <span>{content.length > 36 ? `${content.slice(0, 36)}...` : content}</span>
} else {
return value.type
}
}
const {
key,
currentChannel,
workspaceData,
workspace,
setCurrentChannel,
setCurrentWorkspace,
setParticipants,
resetData
} = props;
const roomData = props.roomData;
const { roomId } = roomData;
return(
<li
className={currentChannel && (roomData.roomId === currentChannel.roomId)
? "active rounded-lg py-1 m-1 bg-card-theme shadow-sm text-theme"
: "rounded-lg py-1 m-1 bg-card-theme shadow-sm text-theme"}
key={key}
onClick={() => {
setCurrentChannel({ ...roomData, roomId })
setCurrentWorkspace({ ...workspaceData, ...workspace })
setParticipants(workspace.workspaceId, roomId)
resetData()
// setLeftPanel(!this.props.displayLeftPanel);
}}
name={roomData.roomName}
active={currentChannel && (roomData.roomId === currentChannel.roomId)}
>
<div className="d-flex align-items-center p-2 w-100">
<div className={roomLiveStatus ? "liveroom" : ""}>
<img
className={roomLiveStatus ? "mr-2 rounded-circle profile-image" : "mr-2 rounded-circle"}
src={roomData.roomPic}
style={{ height: 45, width: 45 }} />
</div>
<div className="flex-grow-1">
<div className="d-flex align-items-center">
{(roomData.roomType === 1)
&& <FontAwesomeIcon
icon={faLock}
className="text-success mr-2"
size="xs" />}
<p className="mb-0 text-theme">{roomData.roomName}</p>
</div>
{roomData.lastMessage
&& <small className="text-theme text-theme-lighter">
<span>{strip(roomData.lastMessage)}</span>
</small>}
</div>
<div className="text-right align-self-start">
{/* <FontAwesomeIcon
icon={faThumbtack}
style={isPinned ? { fontSize: 12, transform: "rotate(45deg)" } : { fontSize: 12 }}
className={isPinned ? "text-theme" : "text-secondary"} /> */}
<p
className="mb-0 text-theme small text-theme-lighter"
style={{ whiteSpace: "nowrap" }}
>
{roomData.lastMessage
&& timeFromNow(roomData.lastMessage.timestamp)}
</p>
{/* Messages Notification */}
{/* <span className="text-white bg-primary smaller font-weight-bold" style={{ whiteSpace: "nowrap", borderRadius: "2px", padding: "3px 3px 3px 3px" }}>
99+</span> */}
</div>
</div>
</li>
)
}
const WorkspaceListElement = (props) => {
const [workspaceData, setWorkspaceData] = useState({});
const [loadingWorkspaceData, setLoadingWorkspaceData] = useState(true);
const [roomsDataArray, setRoomsDataArray] = useState([]);
const [sortingCount, setSortingCount] = useState(0);
const getWorkspaceData = async () => {
const { workspace } = props;
let docRef = await firebase.firestore().collection(`workspaces`).doc(`${workspace.workspaceId}`)
let workspace_data = await docRef.get()
.then(function (doc) {
if (doc.exists) {
// console.log("Document data workspace:", doc.data());
const workspaceData = doc.data()
return workspaceData;
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch(function (error) {
console.log("Error getting document:", error);
})
setWorkspaceData(workspace_data);
setLoadingWorkspaceData(false);
}
const getAllRoomsData = () => {
const { workspace, roomsVisible, setChannels } = props
let roomsArray = []
let roomsDataPromises = []
let roomsDataArray = []
getWorkspaceData()
roomsArray = workspace[roomsVisible] && Object.values(workspace[roomsVisible]).map((room, key) => (
room.roomId
))
// console.log(`roomsArray ${JSON.stringify(roomsArray)}`)
roomsDataPromises = roomsArray.map((roomId, key) => firebase.firestore().collection(`workspaces/${workspace.workspaceId}/rooms`).doc(`${roomId}`).get())
Promise.all(roomsDataPromises).then(values => {
roomsDataArray = values.map(value => {
return { ...value.data(), roomId: value.id }
})
setChannels(roomsDataArray)
})
}
const {
workspace,
_handleAddRoom,
_handleOpenWorkspaceDetails,
roomsVisible,
currentChannel,
allChannels,
searchTerm,
sortType
} = props;
const regex = new RegExp(searchTerm, "gi");
useEffect(() => {
getAllRoomsData()
},[])
useEffect(() => {
getAllRoomsData()
},[props.roomsVisible, props.workspace[props.roomsVisible]])
useEffect(() => {
getWorkspaceData()
},[props.workspace])
useEffect(() => {
console.log('sorttype changed')
switchSort(allChannels, sortType)
setSortingCount((prev) => prev + 1)
},[sortType])
const compareTimestamp = (t1 = null, t2 = null) => {
if (t1 && t2) {return t2.timestamp - t1.timestamp}
if (t1 && t2 == null) {return -1}
if (t2 && t1 == null) {return 1}
return 0
}
const compareTimestampLodashLatestFirst = (allChannels) => {
const sorted = _.orderBy(allChannels, (channel) => {
})
props.setChannels(sorted);
return (sorted);
}
const compareAlphabetLodashAtoZ = (allChannels) => {
const sorted = _.sortBy(allChannels, (channel) => channel.roomName)
// console.log('atoz')
props.setChannels(sorted)
return (sorted);
}
const compareAlphabetLodashZtoA = (allChannels) => {
const sorted = _.sortBy(allChannels, (channel) => channel.roomName)
// console.log('ztoa')
props.setChannels(sorted.reverse())
return (sorted.reverse());
}
const switchSort = (allChannels, sortType) => {
// console.log(allChannels,"allChannels")
switch (sortType) {
case 0:
return compareTimestampLodashLatestFirst(allChannels)
case 1:
return compareAlphabetLodashAtoZ(allChannels)
case 2:
return compareAlphabetLodashZtoA(allChannels)
case 3:
return compareTimestampLodashLatestFirst(allChannels)
default:
return compareTimestampLodashLatestFirst(allChannels)
}
}
// console.log(allChannels,"before return")
return(
<>
{
searchTerm && searchTerm.length > 0
? allChannels
&& allChannels
.filter(item => {
return item.roomName.match(regex) || (item.lastMessage && item.lastMessage.content && item.lastMessage.content.match(regex))
})
.sort((a, b) => switchSort(a, b, sortType))
.map((room, key) => (
<RoomItem
roomData={room}
key={key}
index={key}
currentChannel={currentChannel}
workspace={workspace}
workspaceData={workspaceData}
allChannels={allChannels}
{...props}
/>
))
: allChannels &&
allChannels.map((room, key) => {
return(
<RoomItem
roomData={room}
key={room.roomName + key}
index={key}
currentChannel={currentChannel}
workspace={workspace}
workspaceData={workspaceData}
{...props}
/>
)
})
}
</>
)
}
const mapStateToProps = state => ({
roomsVisible: state.workspace.roomsVisible,
currentChannel: state.channel.currentChannel,
allChannels: state.channel.allChannels,
platform: state.channel.platform
})
export default connect(mapStateToProps, {
setChannels,
setCurrentChannel,
setCurrentWorkspace,
setParticipants,
resetData
})(WorkspaceListElement);
Edit: I fixed it by using lodash cloneDeep. If anyone is stuck in a similar situation refer to this react-redux update item in array doesn't re-render