Contribute page imporvements, sidebar for cards

This commit is contained in:
mrfry 2020-11-30 14:03:13 +01:00
parent db5aad0f8c
commit 1a02ae2e98
13 changed files with 274 additions and 79 deletions

20
src/components/sidebar.js Normal file
View file

@ -0,0 +1,20 @@
import React from 'react'
import styles from './sidebar.module.css'
export default function Sidebar(props) {
const { onClose } = props
return (
<div className={styles.container}>
<div
className={styles.closeBorder}
onClick={() => {
onClose()
}}
>
{'>'}
</div>
<div>{props.children}</div>
</div>
)
}

View file

@ -0,0 +1,25 @@
.container {
background-color: var(--background-color);
border-left: 3px solid #99f;
top: 0;
right: 0px;
height: 100%;
width: 400px;
max-width: 100%;
position: fixed;
display: flex;
}
.closeBorder {
padding: 5px;
cursor: pointer;
display: flex;
flex-flow: column;
justify-content: center;
color: white;
}
.closeBorder:hover {
background-color: #333;
}

View file

@ -3,19 +3,15 @@ import React from 'react'
import styles from './todoCard.module.css'
export default function TodoCard(props) {
const { categories, onClick, userId, clickable } = props
const { name, description, category, points, votes, id } = props.cardData
const { categories, onClick, userId } = props
const { name, category, points, votes, id } = props.cardData
const voted = votes.includes(userId)
return (
<div
className={`${styles.card} ${clickable && styles.clickable} ${voted &&
styles.voted}`}
title={description}
className={`${styles.card} ${voted && styles.voted}`}
onClick={() => {
if (clickable) {
onClick(id)
}
onClick(props.cardData)
}}
>
<div className={styles.description}>

View file

@ -3,17 +3,14 @@
border-radius: 2px;
padding: 5px;
margin: 6px 3px;
cursor: pointer;
}
.voted {
border: 2px solid #cf9;
}
.clickable {
cursor: pointer;
}
.clickable:hover {
.card:hover {
background-color: #333;
border: 2px solid #f99;
}

View file

@ -3,14 +3,16 @@ import React from 'react'
import styles from './todoRow.module.css'
export default function TodoRow(props) {
const { categories, userId } = props
const { name, description, category, votes, id } = props.rowData
const { categories, userId, onClick } = props
const { name, category, votes, id } = props.rowData
const voted = votes.includes(userId)
return (
<div
onClick={() => {
onClick(props.rowData)
}}
className={`${styles.row} ${voted && styles.voted}`}
title={description}
>
<div className={styles.id}>{`#${id}`}</div>
<div className={styles.description}>{name}</div>

View file

@ -4,6 +4,12 @@
border-radius: 2px;
padding: 5px;
margin: 6px 3px;
cursor: pointer;
}
.row:hover {
background-color: #333;
border: 2px solid #f99;
}
.row > div {

View file

@ -0,0 +1,63 @@
import React from 'react'
import styles from './todoSidebar.module.css'
export default function Todos({ card, userId, categories, columns, voteOn }) {
const { name, description, category, points, votes, id } = card
const voteable = columns[card.state].clickable
// TODO: hide vote button if not voteable
return (
<div className={styles.container}>
<div className={styles.name}>
<span className={styles.id}>#{id}</span>
{name}
<span
style={{
margin: '0px 5px',
fontSize: '10px',
backgroundColor: categories[category].color,
color: 'white',
borderRadius: '2px',
padding: '0px 2px',
}}
>
{categories[category].name}
</span>
</div>
<hr />
<div className={styles.row} title={'Minél több a pont, annál nehezebb'}>
<div>Nehézség:</div>
<div>{points}</div>
</div>
<div
className={`${styles.row} ${votes.includes(userId) &&
styles.votedtext}`}
title={'Hány felhasználó szavazott a feladatra'}
>
<div>Szavazatok:</div>
<div>{votes.length}</div>
</div>
<hr />
{description && (
<>
<div className={styles.title}>Leírás</div>
<div dangerouslySetInnerHTML={{ __html: description }} />
<hr />
</>
)}
<div className={styles.category}></div>
{voteable && (
<div
className={`${styles.button} ${votes.includes(userId) &&
styles.voted}`}
onClick={() => {
voteOn(card)
}}
>
{votes.includes(userId) ? 'Szavazat visszavonása' : 'Szavazás'}
</div>
)}
</div>
)
}

View file

@ -0,0 +1,54 @@
.container {
display: flex;
flex-flow: column;
margin: 5px;
}
.container > hr {
width: 100%;
}
.title {
color: #99f;
font-size: 18px;
}
.name {
color: #99f;
font-size: 20px;
margin: 20px 0px;
}
.category {
word-break: break-all;
font-size: 10px;
}
.id {
font-size: 16px;
margin: 0px 3px;
color: #999;
}
.row {
display: flex;
justify-content: space-between;
}
.button {
border: 2px solid #99f;
border-radius: 3px;
text-align: center;
cursor: pointer;
}
.button:hover {
background-color: #333;
}
.votedtext {
color: #cf9;
}
.voted {
border: 2px solid #cf9;
}

View file

@ -5,7 +5,7 @@ import TodoRow from './todoRow.js'
import styles from './todoTable.module.css'
export default function TodoBoard(props) {
const { tables, cards, userId, categories } = props
const { tables, cards, userId, categories, onClick } = props
return (
<div className={styles.tableContainer}>
@ -23,6 +23,7 @@ export default function TodoBoard(props) {
{tableCards.map((card, i) => {
return (
<TodoRow
onClick={onClick}
key={i}
type={key}
rowData={card}

View file

@ -1,8 +1,11 @@
.tableContainer {
overflow-y: hidden;
overflow-x: auto;
margin: 5px 0px;
}
.table {
min-width: 500px;
justify-content: center;
}

View file

@ -3,7 +3,11 @@ import React, { useState, useEffect } from 'react'
import LoadingIndicator from '../LoadingIndicator.js'
import TodoBoard from './todoBoard.js'
import TodoTable from './todoTable.js'
import TodoSidebar from './todoSidebar.js'
import Sidebar from '../sidebar.js'
// import styles from './todos.module.css'
import constants from '../../constants.json'
const byVotes = (a, b) => {
@ -13,11 +17,10 @@ const byVotes = (a, b) => {
export default function Todos() {
const [loaded, setLoaded] = useState(false)
const [columns, setColumns] = useState(null)
const [boardCards, setBoardCards] = useState(null)
const [tables, setTables] = useState(null)
const [tableCards, setTableCards] = useState(null)
const [cards, setCards] = useState(null)
const [categories, setCategories] = useState(null)
const [userId, setUserId] = useState(null)
const [sidebarCard, setSidebarCard] = useState(null)
useEffect(() => {
console.info('Fetching todos')
@ -36,72 +39,98 @@ export default function Todos() {
setCategories(data.todos.categories)
setUserId(data.userId)
let bCards = []
let tCards = []
data.todos.cards.forEach((card) => {
if (data.todos.columns[card.state].type === 'table') {
tCards.push(card)
} else {
bCards.push(card)
}
})
setTableCards(tCards.sort(byVotes))
setBoardCards(bCards.sort(byVotes))
let cols = {}
let tables = {}
Object.keys(data.todos.columns).forEach((key) => {
const col = data.todos.columns[key]
if (col.type !== 'table') {
cols = {
...cols,
[key]: col,
}
} else {
tables = {
...tables,
[key]: col,
}
}
})
setColumns(cols)
setTables(tables)
setCards(data.todos.cards)
setColumns(data.todos.columns)
setLoaded(true)
}
const onCardClick = (id) => {
fetch(`${constants.apiUrl}todos?id=${id}`, {
credentials: 'include',
})
.then((resp) => {
return resp.json()
})
.then((data) => {
setTodos(data)
})
const onClick = (card) => {
setSidebarCard(card.id)
}
if (!loaded) {
return <LoadingIndicator />
}
let bCards = []
let tCards = []
cards.forEach((card) => {
if (columns[card.state].type === 'table') {
tCards.push(card)
} else {
bCards.push(card)
}
})
bCards = bCards.sort(byVotes)
tCards = tCards.sort(byVotes)
let cols = {}
let tables = {}
Object.keys(columns).forEach((key) => {
const col = columns[key]
if (col.type !== 'table') {
cols = {
...cols,
[key]: col,
}
} else {
tables = {
...tables,
[key]: col,
}
}
})
return (
<div>
<TodoBoard
columns={columns}
cards={boardCards}
userId={userId}
categories={categories}
onCardClick={onCardClick}
/>
<TodoTable
tables={tables}
cards={tableCards}
userId={userId}
categories={categories}
/>
{sidebarCard && (
<Sidebar
onClose={() => {
setSidebarCard(null)
}}
>
<TodoSidebar
card={cards.find((card) => {
return card.id === sidebarCard
})}
userId={userId}
categories={categories}
columns={columns}
voteOn={(card) => {
fetch(`${constants.apiUrl}todos?id=${card.id}`, {
credentials: 'include',
})
.then((resp) => {
return resp.json()
})
.then((data) => {
setTodos(data)
})
}}
/>
</Sidebar>
)}
<div
style={{
// width: '100%',
marginRight: sidebarCard ? 380 : 0,
}}
>
<TodoBoard
columns={cols}
cards={bCards}
userId={userId}
categories={categories}
onCardClick={onClick}
/>
<TodoTable
tables={tables}
cards={tCards}
userId={userId}
categories={categories}
onClick={onClick}
/>
</div>
</div>
)
}

View file

@ -62,10 +62,9 @@ export default function contribute() {
return (
<div>
<div className={styles.description}>
Egy kártyára kattintva szavazhatsz. Minél több szavazat érkezik egy
kártyára, annál magasabb lesz a pioritása. Jobb alsó szám minél több,
annál nehezebb a feladat. Tartsd egeret kártyán részletesebb leírásért
(ha van hozzá)
Egy kártyára kattintva nézheted meg a részleteket, vagy szavazhatsz.
Minél több szavazat érkezik egy kártyára, annál magasabb lesz a
pioritása. Jobb alsó szám minél több, annál nehezebb a feladat.
</div>
<Todos />
<div className={styles.description}>Itt írhatsz todo-ra ötleteket </div>