Skip to content

Commit

Permalink
Add TaskDeadlineDrawer (#1166)
Browse files Browse the repository at this point in the history
* design-library: Add task-deadline-drawer

* task-deadline-form, task: Use task-deadline-drawer

* translations: Add clear deadline

* task, task-deadline-form: Readjust stylings for btn and label
  • Loading branch information
hemangsk authored Jan 11, 2025
1 parent 88e7b53 commit 501756f
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react'
import Drawer from '../../molecules/drawer/drawer'
import TaskDeadlineForm from '../../../task/task-deadline-form'

type TaskDeadlineDrawerProps = {
open: boolean
onClose: () => void
taskId: number
task: any
onUpdate: (task: any) => void
classes?: any
}

const TaskDeadlineDrawer = ({
open,
onClose,
taskId,
task,
onUpdate,
classes
}: TaskDeadlineDrawerProps) => {
return (
<Drawer
open={open}
onClose={onClose}
title="Set task deadline"
>
<TaskDeadlineForm
match={{ params: { id: taskId } }}
classes={classes}
open={open}
task={task}
updateTask={(task) => {
onUpdate(task)
onClose()
}}
/>
</Drawer>
)
}

export default TaskDeadlineDrawer
184 changes: 112 additions & 72 deletions frontend/src/components/task/task-deadline-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl'
import MomentComponent from 'moment'
import { withStyles } from '@material-ui/core/styles'

import {
Card,
CardContent,
CardMedia,
Typography,
Button,
Expand Down Expand Up @@ -39,12 +38,32 @@ const messages = defineMessages({
},
})

const styles = theme => ({
btnClearDeadline: {
float: 'left',
marginTop: 10,
color: theme.palette.error.main,
borderColor: theme.palette.error.main
},
dayLabel: {
marginTop: 0,
marginLeft: '2em'
}
})

class TaskDeadlineForm extends Component {
constructor (props) {
constructor(props) {
super(props)
this.state = {
deadline: null,
open: false
deadline: props.task?.deadline || null,
open: false,
dateChanged: false
}
}

componentDidUpdate(prevProps) {
if (prevProps.task?.deadline !== this.props.task?.deadline) {
this.setState({ deadline: this.props.task?.deadline || null })
}
}

Expand All @@ -65,7 +84,10 @@ class TaskDeadlineForm extends Component {
id: this.props.match.params.id,
deadline: this.state.deadline
})
this.setState({ open: true })
this.setState({
open: true,
dateChanged: false
})
}

pickTaskDeadline = (time) => {
Expand All @@ -77,83 +99,100 @@ class TaskDeadlineForm extends Component {
}

handleInputChangeCalendar = (e) => {
this.setState({ deadline: e.target.value })
this.setState({ deadline: e.target.value, dateChanged: true })
}

handleClearDeadline = () => {
this.props.updateTask({
id: this.props.match.params.id,
deadline: null
})
this.setState({ deadline: null })
}

renderChip (label, value) {
renderChip(label, value) {
return (
<Chip
style={ { marginBottom: 20 } }
label={ label }
className={ this.props.classes.chip }
onClick={ () => this.pickTaskDeadline(value) }
style={{ marginBottom: 20 }}
label={label}
className={this.props.classes.chip}
onClick={() => {
this.pickTaskDeadline(value)
this.setState({ dateChanged: false })
}}
/>
)
}

render () {
render() {
const { classes, intl } = this.props

return (
<div>
<Collapse in={ !!this.props.open }>
<Card className={ classes.card }>
<FormattedMessage id='task.status.deadline.subheading.main' defaultMessage='Choose a date that this task should be finished'>
{ (msg) => (
<CardMedia
className={ classes.cover }
image={ timeIcon }
title={ msg }
/>
) }
</FormattedMessage>
<div className={ classes.details }>
<CardContent className={ classes.content }>
<Typography variant='h5'>
<FormattedMessage id='task.status.deadline.headline' defaultMessage='Finish date' />
</Typography>
<Typography variant='body1' color='textSecondary'>
<FormattedMessage id='task.status.deadline.subheading' defaultMessage='Choose a date that this task should be finished' />,
</Typography>
<div className={ classes.chipContainer }>
{ [{ label: intl.formatMessage(messages.deadlineLevel1), value: 7 }, { label: intl.formatMessage(messages.deadlineLevel2), value: 15 }, { label: intl.formatMessage(messages.deadlineLevel3), value: 20 }, { label: intl.formatMessage(messages.deadlineLevel4), value: 30 }].map((item, index) => {
return this.renderChip(item.label, item.value)
})
}
</div>
<form className={ classes.formPayment } action='POST'>
<FormControl fullWidth>
<FormattedMessage id='task.status.deadline.day.label' defaultMessage='Day'>
{ (msg) => (
<InputLabel htmlFor='adornment-amount'>{ msg }</InputLabel>
) }
</FormattedMessage>
<FormattedMessage id='task.status.deadline.day.insert.label' defaultMessage='Choose a date'>
{ (msg) => (
<Input
id='adornment-date'
startAdornment={ <InputAdornment position='start'><DateIcon /></InputAdornment> }
placeholder={ msg }
type='date'
value={ `${MomentComponent(this.state.deadline).format('YYYY-MM-DD')}` || `${MomentComponent().format('YYYY-MM-DD')}` }
onChange={ this.handleInputChangeCalendar }
/>
) }
</FormattedMessage>
</FormControl>
<Button disabled={ !this.state.deadline } onClick={ this.handleDeadline } variant='contained' color='primary' className={ classes.btnPayment }>
{ this.state.deadline
? <FormattedMessage id='task.status.deadline.set.target' defaultMessage='set to target date to {date}' values={ {
date: MomentComponent(this.state.deadline).format('MM/DD/YYYY')
} } />
: <FormattedMessage id='task.deadline.button.save' defaultMessage='Save date' />
}
</Button>
</form>
</CardContent>
<div className={ classes.controls } />
<Collapse in={!!this.props.open}>
<FormattedMessage id='task.status.deadline.subheading.main' defaultMessage='Choose a date that this task should be finished'>
{(msg) => (
<CardMedia
className={classes.cover}
image={timeIcon}
title={msg}
/>
)}
</FormattedMessage>
<div className={classes.details}>
<Typography variant='h5'>
<FormattedMessage id='task.status.deadline.headline' defaultMessage='Finish date' />
</Typography>
<Typography variant='body1' color='textSecondary'>
<FormattedMessage id='task.status.deadline.subheading' defaultMessage='Choose a date that this task should be finished' />,
</Typography>
<div className={classes.chipContainer}>
{[{ label: intl.formatMessage(messages.deadlineLevel1), value: 7 }, { label: intl.formatMessage(messages.deadlineLevel2), value: 15 }, { label: intl.formatMessage(messages.deadlineLevel3), value: 20 }, { label: intl.formatMessage(messages.deadlineLevel4), value: 30 }].map((item, index) => {
return this.renderChip(item.label, item.value)
})
}
</div>
</Card>
<form className={classes.formPayment} action='POST'>
<FormControl fullWidth>
<FormattedMessage id='task.status.deadline.day.label' defaultMessage='Day'>
{(msg) => (
<InputLabel htmlFor='adornment-date' className={classes.dayLabel}>{msg}</InputLabel>
)}
</FormattedMessage>
<FormattedMessage id='task.status.deadline.day.insert.label' defaultMessage='Choose a date'>
{(msg) => (
<Input
id='adornment-date'
startAdornment={<InputAdornment position='start'><DateIcon /></InputAdornment>}
placeholder={msg}
type='date'
value={`${MomentComponent(this.state.deadline).format('YYYY-MM-DD')}` || `${MomentComponent().format('YYYY-MM-DD')}`}
onChange={this.handleInputChangeCalendar}
/>
)}
</FormattedMessage>
</FormControl>
<Button disabled={!this.state.deadline} onClick={this.handleDeadline} variant='contained' color='primary' className={classes.btnPayment}>
{this.state.deadline && this.state.dateChanged
? <FormattedMessage id='task.status.deadline.set.target' defaultMessage='set to target date to {date}' values={{
date: MomentComponent(this.state.deadline).format('MM/DD/YYYY')
}} />
: <FormattedMessage id='task.deadline.button.save' defaultMessage='Save date' />
}
</Button>
{this.state.deadline && (
<Button
onClick={this.handleClearDeadline}
variant='outlined'
color='secondary'
className={classes.btnClearDeadline}
>
<FormattedMessage id='task.deadline.button.clear' defaultMessage='Clear deadline' />
</Button>
)}
</form>
<div className={classes.controls} />
</div>
</Collapse>
</div>
)
Expand All @@ -164,7 +203,8 @@ TaskDeadlineForm.propTypes = {
updateTask: PropTypes.func.isRequired,
match: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
open: PropTypes.bool
open: PropTypes.bool,
task: PropTypes.object
}

export default injectIntl(TaskDeadlineForm)
export default injectIntl(withStyles(styles)(TaskDeadlineForm))
40 changes: 27 additions & 13 deletions frontend/src/components/task/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ import TaskStatusIcons from './task-status-icons'

import Constants from '../../consts'

import TaskDeadlineDrawer from '../design-library/templates/task-deadline-drawer/task-deadline-drawer'

const taskCover = require('../../images/task-cover.png')
const inviteCover = require('../../images/funds.png')

Expand Down Expand Up @@ -1047,12 +1049,19 @@ class Task extends Component {
</Typography>
<div>
<Typography variant='h6' className={classes.taskInfoContent}>
<div>
<div>{deliveryDate}</div>
{deadline && parseInt(deadline) > 0 ? <small>in {deadline} days</small>
: <Chip size='small' label={<FormattedMessage id='task.dealine.past' defaultMessage='Overdue' />} />
}
</div>
<Button onClick={() => this.setState({ deadlineForm: true })}>
{task.data.deadline ? (
<div>
<div>{deliveryDate}</div>
{deadline && parseInt(deadline) > 0 ?
<small>in {deadline} days</small>
: <Chip size='small' label={<FormattedMessage id='task.dealine.past' defaultMessage='Overdue' />} />
}
</div>
) : (
<FormattedMessage id='task.deadline.call' defaultMessage='Set deadline' />
)}
</Button>
</Typography>
</div>
</div>
Expand All @@ -1076,30 +1085,35 @@ class Task extends Component {
</Typography>
<div>
<Typography variant='h6' className={classes.taskInfoContent}>
<Button onClick={() => this.setState({ deadlineForm: !this.state.deadlineForm })}>
<Button onClick={() => this.setState({ deadlineForm: true })}>
{task.data.deadline ? (
<div>
<div>{deliveryDate}</div>
{deadline && parseInt(deadline) > 0 ? <small>in {deadline} days</small>
{deadline && parseInt(deadline) > 0 ?
<small>in {deadline} days</small>
: <Chip size='small' label={<FormattedMessage id='task.dealine.past' defaultMessage='Overdue' />} />
}
</div>
) : (
<FormattedMessage id='task.deadline.call' defaultMessage='Set deadline' />
)}

</Button>
</Typography>
</div>
</div>
}
</div>
<div>
<TaskDeadlineForm match={{ params: { id: task.data.id } }} classes={classes} open={this.state.deadlineForm} updateTask={(task) => {
<TaskDeadlineDrawer
open={this.state.deadlineForm}
onClose={() => this.setState({ deadlineForm: false })}
taskId={task.data.id}
task={task.data}
onUpdate={(task) => {
this.props.updateTask(task)
this.setState({ deadlineForm: false })
}} />
</div>
}}
classes={classes}
/>
{task?.data && (task?.data?.orders?.length || task?.data?.Orders?.length) ?
<div>
<TaskPayments orders={(task?.data?.orders || task?.data?.Orders)?.filter(o => o.paid && o.status === 'succeeded')} />
Expand Down
1 change: 1 addition & 0 deletions frontend/src/translations/br.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"task.status.deadline.day.insert.label": "Escolha uma data",
"task.status.deadline.set.target": "Escolher data para {date}",
"task.deadline.button.save": "Salvar data",
"task.deadline.button.clear": "Limpar data",
"task.invite.title": "Convide alguém para trabalhar nesta tarefa",
"task.funding.title": "Convide alguém para adicionar uma recompensa para essa tarefa",
"task.invite.text.label": "Escreva um texto para ser enviado junto ao convite",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
"task.status.deadline.day.insert.label": "Choose a date",
"task.status.deadline.set.target": "Set deadline to {date}",
"task.deadline.button.save": "Save date",
"task.deadline.button.clear": "Clear deadline",
"task.invite.title": "Invite someone to work on this task",
"task.funding.title": "Invite someone to add bounties to this issue",
"task.invite.text.label": "Write an invitation text",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/translations/generated/br.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
"task.claim.form.send": "",
"task.claim.subtitle": "",
"task.claim.title": "",
"task.deadline.button.clear": "",
"task.deadline.button.save": "",
"task.deadline.call": "",
"task.deadline.label": "",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/translations/generated/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
"task.claim.form.send": "Claim",
"task.claim.subtitle": "If you're the original author of this issue, you can claim this issue so you will be admin and transfer the property to manage the issue on Gitpay.",
"task.claim.title": "Claim issue",
"task.deadline.button.clear": "Clear deadline",
"task.deadline.button.save": "Save date",
"task.deadline.call": "Set deadline",
"task.deadline.label": "Deadline",
Expand Down

0 comments on commit 501756f

Please sign in to comment.