mirror of
https://gitlab.com/MrFry/qmining-page
synced 2025-04-01 20:23:44 +02:00
Contribute page imporvements, sidebar for cards
This commit is contained in:
parent
db5aad0f8c
commit
1a02ae2e98
13 changed files with 274 additions and 79 deletions
20
src/components/sidebar.js
Normal file
20
src/components/sidebar.js
Normal 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>
|
||||
)
|
||||
}
|
25
src/components/sidebar.module.css
Normal file
25
src/components/sidebar.module.css
Normal 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;
|
||||
}
|
|
@ -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}>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
63
src/components/todoStuff/todoSidebar.js
Normal file
63
src/components/todoStuff/todoSidebar.js
Normal 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>
|
||||
)
|
||||
}
|
54
src/components/todoStuff/todoSidebar.module.css
Normal file
54
src/components/todoStuff/todoSidebar.module.css
Normal 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;
|
||||
}
|
|
@ -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}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
.tableContainer {
|
||||
overflow-y: hidden;
|
||||
overflow-x: auto;
|
||||
margin: 5px 0px;
|
||||
}
|
||||
|
||||
.table {
|
||||
min-width: 500px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
0
src/components/todoStuff/todos.module.css
Normal file
0
src/components/todoStuff/todos.module.css
Normal 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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue