From 0ef81bb4fa3755003a33032d37ce30ffa6a1b8d0 Mon Sep 17 00:00:00 2001 From: Alexandre Magno Date: Sun, 24 Nov 2024 03:02:18 +0100 Subject: [PATCH 1/3] improving offer component and moving offers to the right section --- .../offers-list/offers-list.stories.tsx | 29 ++++ .../molecules/offers-list/offers-list.tsx | 107 +++++++++++++++ .../components/invite/invite-input.tsx | 23 ++++ .../components/offer-drawer-create.tsx | 127 +++++++++++++++++ .../components/offer-drawer-tabs.tsx | 27 ++++ .../offer-drawer/offer-drawer.stories.tsx | 18 +++ .../templates/offer-drawer/offer-drawer.tsx | 129 +++++++----------- frontend/src/components/task/task.js | 4 + modules/tasks/taskFetch.js | 3 +- 9 files changed, 386 insertions(+), 81 deletions(-) create mode 100644 frontend/src/components/design-library/molecules/offers-list/offers-list.stories.tsx create mode 100644 frontend/src/components/design-library/molecules/offers-list/offers-list.tsx create mode 100644 frontend/src/components/design-library/templates/offer-drawer/components/invite/invite-input.tsx create mode 100644 frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-create.tsx create mode 100644 frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx diff --git a/frontend/src/components/design-library/molecules/offers-list/offers-list.stories.tsx b/frontend/src/components/design-library/molecules/offers-list/offers-list.stories.tsx new file mode 100644 index 00000000..42919e42 --- /dev/null +++ b/frontend/src/components/design-library/molecules/offers-list/offers-list.stories.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import OffersList from './offers-list'; + +export default { + title: 'Design Library/Molecules/OffersList', + component: OffersList, +}; + +const Template = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + offers: [ + { + User: { + username: 'username', + picture_url: 'https://via.placeholder.com/150', + name: 'name', + }, + status: 'status', + value: 100, + suggestedDate: new Date(), + }, + ], + onMessage: (id) => console.log('onMessage', id), + assigned: false, + onAccept: (id) => console.log('onAccept', id), + onReject: (id) => console.log('onReject', id), +}; \ No newline at end of file diff --git a/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx b/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx new file mode 100644 index 00000000..ef9b0d77 --- /dev/null +++ b/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx @@ -0,0 +1,107 @@ +import React from 'react'; +import { + Button, + Chip, + Typography, + List, + ListItem, + ListItemText, + ListItemAvatar, + Avatar, + Divider +} from '@material-ui/core'; +import MessageIcon from '@mui/icons-material/Message'; +import MomentComponent from 'moment'; +import { FormattedMessage } from 'react-intl'; + +interface OfferListProps { + offers: any; + onMessage?: any; + assigned?: boolean; + onAccept?: any; + onReject?: any; +} + + +export default function OffersList({ offers, onMessage, assigned, onAccept, onReject }:OfferListProps) { + const onSendMessage = (id) => { + onMessage(id); + } + + return ( + + {offers?.map((offer) => ( + <> + + + + + + {offer?.User?.username || offer?.User?.name} + + + } + secondary={ +
+
+ + { offer?.User?.name } + + + $ {offer?.value} + + { offer?.suggestedDate && + + Finish {MomentComponent(offer?.suggestedDate).fromNow()} + + } + { offer?.comment && + + Comment:
+ {offer?.comment} +
+ } + { offer?.learn && + + + + } + { offer?.createdAt && + + { MomentComponent(offer?.createdAt).fromNow() } + + } +
+
+ + + +
+
+ } + /> +
+ + + ))} +
+ ); +} \ No newline at end of file diff --git a/frontend/src/components/design-library/templates/offer-drawer/components/invite/invite-input.tsx b/frontend/src/components/design-library/templates/offer-drawer/components/invite/invite-input.tsx new file mode 100644 index 00000000..37755e6a --- /dev/null +++ b/frontend/src/components/design-library/templates/offer-drawer/components/invite/invite-input.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { FormControl, Input, InputLabel } from "@material-ui/core"; + +const EmailInviteInput = ({ + onEmailInviteChange +}) => { + return ( + + + + + + + ) +} + +export default EmailInviteInput; \ No newline at end of file diff --git a/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-create.tsx b/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-create.tsx new file mode 100644 index 00000000..c7edd759 --- /dev/null +++ b/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-create.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import Introduction from '../../../molecules/introduction/introduction'; +import IssueCard from '../../../organisms/issue-card/issue-card'; +import SimpleInfo from '../../../molecules/simple-info/simple-info'; +import DeliveryDate from '../../../organisms/delivery-date/delivery-date'; +import PickupTagList from '../../../molecules/pickup-tag-list/pickup-tag-list'; +import PricePlan from '../../../organisms/price-plan/price-plan'; +import InputComment from '../../../molecules/input-comment/input-comment'; +import OfferDrawerCheckboxes from './offer/offer-drawer-checkboxes'; +import InviteInput from './invite/invite-input'; +import { makeStyles } from '@material-ui/core'; +import CheckboxTerms from '../../../molecules/checkbox-terms/checkbox-terms'; + +const useStyles = makeStyles(theme => ({ + details: { + display: 'flex', + flexDirection: 'column' + }, + spanText: { + display: 'inline-block', + verticalAlign: 'middle' + }, +})); + +interface OfferDrawerCreateProps { + introTitle: any; + introMessage: any; + introImage: any; + issue: any; + simpleInfoText: any; + commentAreaPlaceholder: any; + onDeliveryDateChange: any; + pickupTagListTitle: any; + pickutTagListDescription: any; + setCurrentPrice: any; + currentPrice: any; + onCommentChange: any; + offerCheckboxes: boolean; + onLearnCheckboxChange: any; + onConfirmOfferChange: any; + onTermsCheckboxChange: any; + onEmailInviteChange: any; + hasEmailInput?: boolean; +} + +const OfferDrawerCreate: React.FC = ({ + introTitle, + introMessage, + introImage, + issue, + simpleInfoText, + commentAreaPlaceholder, + onDeliveryDateChange, + pickupTagListTitle, + pickutTagListDescription, + setCurrentPrice, + currentPrice, + onCommentChange, + offerCheckboxes, + onLearnCheckboxChange, + onConfirmOfferChange, + onTermsCheckboxChange, + onEmailInviteChange, + hasEmailInput = false +}) => { + + const classes = useStyles(); + + return ( + <> + + + {introMessage} + + + + + {hasEmailInput && } + + setCurrentPrice(price)} + /> + , + title: , + items: [ + , + , + ], + } + } price={currentPrice} onChange={(price) => setCurrentPrice(price)} /> + + {offerCheckboxes && + + } + + + ); +}; + +export default OfferDrawerCreate; \ No newline at end of file diff --git a/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx b/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx new file mode 100644 index 00000000..931e2d44 --- /dev/null +++ b/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx @@ -0,0 +1,27 @@ +import React, { useState } from 'react'; +import { Tab, Tabs } from "@material-ui/core"; + + +const OfferDrawerTabs = ({ tabs }) => { + const [tabValue, setTabValue] = useState(0) + + const handleChange = (event, newValue) => { + setTabValue(newValue) + } + + return ( + <> + + {tabs.map((tab) => )} + + {tabs.map((tab) => tab.value === tabValue && tab.component)} + + ); +} + +export default OfferDrawerTabs; \ No newline at end of file diff --git a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.stories.tsx b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.stories.tsx index ad2e4c94..08740895 100644 --- a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.stories.tsx +++ b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.stories.tsx @@ -58,3 +58,21 @@ Primary.args = { } } }; + +export const WithTabs = Template.bind({}); +WithTabs.args = { + ...Primary.args, + offers: [ + { + User: { + username: 'username', + picture_url: 'https://via.placeholder.com/150', + name: 'name', + }, + status: 'status', + value: 100, + suggestedDate: new Date(), + }, + ], + tabs: true, +}; diff --git a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx index 196262a6..7efdddad 100644 --- a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx +++ b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx @@ -1,20 +1,10 @@ import React, { useEffect } from 'react' -import { FormattedMessage } from 'react-intl' import { makeStyles } from '@material-ui/core/styles'; import Drawer from '../../molecules/drawer/drawer' - -import Introduction from '../../molecules/introduction/introduction'; -import IssueCard from '../../organisms/issue-card/issue-card'; -import SimpleInfo from '../../molecules/simple-info/simple-info'; -import DeliveryDate from '../../organisms/delivery-date/delivery-date'; -import PickupTagList from '../../molecules/pickup-tag-list/pickup-tag-list'; -import { FormControl, Input, InputLabel, Typography } from '@material-ui/core'; -import PricePlan from '../../organisms/price-plan/price-plan'; -import InputComment from '../../molecules/input-comment/input-comment'; -import OfferDrawerCheckboxes from './components/offer/offer-drawer-checkboxes'; -import OfferDrawerActions from './components/offer/offer-drawer-actions'; -import CheckboxTerms from '../../molecules/checkbox-terms/checkbox-terms'; +import OfferDrawerCreate from './components/offer-drawer-create'; +import OfferDrawerTabs from './components/offer-drawer-tabs'; +import OffersList from '../../molecules/offers-list/offers-list'; const useStyles = makeStyles(theme => ({ @@ -50,6 +40,8 @@ type OfferDrawerProps = { onTermsCheckboxChange?: any; onConfirmOfferChange: any; onEmailInviteChange?: any; + tabs?: any; + offersProps?: any; } const OfferDrawer = ({ @@ -73,29 +65,49 @@ const OfferDrawer = ({ onCommentChange, onTermsCheckboxChange, onConfirmOfferChange, - onEmailInviteChange + onEmailInviteChange, + tabs, + offersProps }: OfferDrawerProps) => { const [ currentPrice, setCurrentPrice ] = React.useState(0); const classes = useStyles(); - const emailInviteInput = () => { - if (hasEmailInput) { - return ( - - - - - - - ) + const createSection = + + + const drawerTabs = [ + { + value: 0, + label: 'Your existing offers', + default: true, + component: + }, + { + value: 1, + label: 'Make a new offer', + component: createSection } - } + ] useEffect(() => { onChangePrice?.(currentPrice) @@ -108,57 +120,14 @@ const OfferDrawer = ({ actions={actions} title={title} > - - - {introMessage} - - - - - { emailInviteInput() } - - setCurrentPrice(price)} - /> - , - title: , - items: [ - , - , - ], - } - } price={currentPrice} onChange={(price) => setCurrentPrice(price)} /> - - { offerCheckboxes && - + {tabs ? +
+ +
+ :
+ {createSection} +
} - ) } diff --git a/frontend/src/components/task/task.js b/frontend/src/components/task/task.js index 6b4bf689..befba26b 100644 --- a/frontend/src/components/task/task.js +++ b/frontend/src/components/task/task.js @@ -1242,6 +1242,10 @@ class Task extends Component { onTermsCheckboxChange={(checked) => this.setState({ termsAgreed: checked })} onConfirmOfferChange={(checked) => this.setState({ confirmOffer: checked })} onCommentChange={(e) => this.setState({ interestedComment: e.target.value })} + tabs={true} + offersProps={{ + offers: task.data.Offers + }} /> Date: Sun, 24 Nov 2024 16:29:32 +0100 Subject: [PATCH 2/3] getting offers component working properly, accepting, rejecting and sending messages --- .../components/offer-drawer-tabs.tsx | 3 +- .../templates/offer-drawer/offer-drawer.tsx | 19 +- .../task/offers/task-offer-drawer.tsx | 192 ++++++++++++ frontend/src/components/task/task-payment.js | 276 ++++++++---------- frontend/src/components/task/task.js | 71 +---- 5 files changed, 345 insertions(+), 216 deletions(-) create mode 100644 frontend/src/components/task/offers/task-offer-drawer.tsx diff --git a/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx b/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx index 931e2d44..5387b501 100644 --- a/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx +++ b/frontend/src/components/design-library/templates/offer-drawer/components/offer-drawer-tabs.tsx @@ -2,11 +2,12 @@ import React, { useState } from 'react'; import { Tab, Tabs } from "@material-ui/core"; -const OfferDrawerTabs = ({ tabs }) => { +const OfferDrawerTabs = ({ tabs, onTabChange }) => { const [tabValue, setTabValue] = useState(0) const handleChange = (event, newValue) => { setTabValue(newValue) + onTabChange(newValue) } return ( diff --git a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx index 7efdddad..3f72df42 100644 --- a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx +++ b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx @@ -5,6 +5,7 @@ import Drawer from '../../molecules/drawer/drawer' import OfferDrawerCreate from './components/offer-drawer-create'; import OfferDrawerTabs from './components/offer-drawer-tabs'; import OffersList from '../../molecules/offers-list/offers-list'; +import { AddCircleTwoTone as AddIcon } from '@material-ui/icons'; const useStyles = makeStyles(theme => ({ @@ -18,7 +19,7 @@ const useStyles = makeStyles(theme => ({ }, })); -type OfferDrawerProps = { +export type OfferDrawerProps = { title: any; introTitle: any; introMessage: any; @@ -70,6 +71,7 @@ const OfferDrawer = ({ offersProps }: OfferDrawerProps) => { const [ currentPrice, setCurrentPrice ] = React.useState(0); + const [ enableActions, setEnableActions ] = React.useState(false); const classes = useStyles(); @@ -104,7 +106,12 @@ const OfferDrawer = ({ }, { value: 1, - label: 'Make a new offer', + label: ( +
+ Make a new offer + +
+ ), component: createSection } ] @@ -113,16 +120,20 @@ const OfferDrawer = ({ onChangePrice?.(currentPrice) }, [currentPrice]) + useEffect(() => { + tabs && setEnableActions(false) + }, [tabs]) + return ( {tabs ?
- + value !== 0 ? setEnableActions(true) : setEnableActions(false)} />
:
{createSection} diff --git a/frontend/src/components/task/offers/task-offer-drawer.tsx b/frontend/src/components/task/offers/task-offer-drawer.tsx new file mode 100644 index 00000000..c2e9060e --- /dev/null +++ b/frontend/src/components/task/offers/task-offer-drawer.tsx @@ -0,0 +1,192 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import OfferDrawer, { type OfferDrawerProps } from '../../design-library/templates/offer-drawer/offer-drawer'; +import { makeStyles, Typography, } from '@material-ui/core'; +import TaskOrderInvoiceConfirm from '../task-order-invoice-confirm'; +import MessageAssignment from '../assignment/messageAssignment'; +const taskCover = require('../../../images/task-cover.png') + +const useStyles = makeStyles(theme => ({ + spanText: { + display: 'inline-block', + verticalAlign: 'middle' + }, +})); + +type TaskOfferDrawerProps = { + issue: any; + open: boolean; + onClose: any; + onMessage: any; + assigned: boolean; + handleOfferTask: any; + offerUpdate: any; + loggedUser: any; + createOrder: any; + assignTask: any; + assigns: any; +} + +const TaskOfferDrawer = ({ + issue, + open, + onClose, + onMessage, + assigned, + handleOfferTask, + offerUpdate, + loggedUser, + createOrder, + assignTask, + assigns +}: TaskOfferDrawerProps +) => { + const classes = useStyles(); + + const { data } = issue + + const [interestedSuggestedDate, setInterestedSuggestedDate] = React.useState(null); + const [currentPrice, setCurrentPrice] = React.useState(null); + const [interestedComment, setInterestedComment] = React.useState(''); + const [interestedLearn, setInterestedLearn] = React.useState(false); + const [termsAgreed, setTermsAgreed] = React.useState(false); + const [confirmOffer, setConfirmOffer] = React.useState(false); + const [confirmOrderDialog, setConfirmOrderDialog] = React.useState(false); + const [currentOffer, setCurrentOffer] = React.useState(null); + const [messageDialog, setMessageDialog] = React.useState(false); + const [ interested, setInterested ] = React.useState(null) + + const confirmAssignTaskAndCreateOrder = async (event, offer) => { + event.preventDefault() + setConfirmOrderDialog(true) + setCurrentOffer(offer) + } + + const onReject = async (event, offer) => { + event.preventDefault() + offerUpdate(data.id, offer.id, { status: 'rejected' }) + } + + const assignTaskAndCreateOrder = async (event, offer) => { + event.preventDefault() + + const assign = assigns.filter(item => item.userId === offer.userId)[0] + + await data.id && loggedUser.logged && await createOrder({ + provider: 'stripe', + amount: offer.value, + userId: loggedUser?.user?.id, + email: loggedUser?.user?.email, + taskId: data.id, + currency: 'usd', + status: 'open', + source_type: 'invoice-item', + customer_id: loggedUser?.user?.customer_id, + metadata: { + offer_id: data.id, + } + }) + await assignTask(data.id, assign.id) + await offerUpdate(data.id, offer.id, { status: 'accepted' }) + setConfirmOrderDialog(false) + setCurrentOffer(null) + } + + const openMessageDialog = (id) => { + setMessageDialog(true) + setInterested(id) + } + + const userOffers = data?.Offers?.filter(offer => offer.User.id === loggedUser?.user?.id) || [] + + return ( + <> + setMessageDialog(false) } + id={ data.id } + to={ interested } + messageAction={ onMessage } + /> + setConfirmOrderDialog(false)} + onConfirm={(event) => assignTaskAndCreateOrder(event, currentOffer)} + offer={currentOffer} + /> + } + introTitle={ + + } + introMessage={ + + {(msg) => ( + + {msg} + + )} + + } + pickupTagListTitle={ + + + + } + pickutTagListDescription={ + + + + } + simpleInfoText={ + + {(msg) => ( + + {msg} + + )} + + } + commentAreaPlaceholder={ + + } + introImage={taskCover} + issue={issue} + open={open} + onClose={onClose} + actions={ + [ + { + label: , + onClick: onClose + }, + { + label: , + onClick: handleOfferTask, + variant: 'contained', + color: 'secondary', + disabled: confirmOffer || termsAgreed || currentPrice || currentPrice === 0 + } + ] + } + onDeliveryDateChange={(date) => setInterestedSuggestedDate(date)} + onChangePrice={(price) => setCurrentPrice(price)} + onLearnCheckboxChange={(checked) => setInterestedLearn(checked)} + onTermsCheckboxChange={(checked) => setTermsAgreed(checked)} + onConfirmOfferChange={(checked) => setConfirmOffer(checked)} + onCommentChange={(e) => setInterestedComment(e.target.value)} + tabs={!!userOffers.length} + offersProps={{ + offers: userOffers, + onMessage: (id) => openMessageDialog(id), + assigned: assigned, + onAccept: (event, offer) => confirmAssignTaskAndCreateOrder(event, offer), + onReject: (event, offer) => onReject(event, offer) + }} + /> + + ); +} + +export default TaskOfferDrawer; \ No newline at end of file diff --git a/frontend/src/components/task/task-payment.js b/frontend/src/components/task/task-payment.js index 7b38e4e6..15fdb673 100644 --- a/frontend/src/components/task/task-payment.js +++ b/frontend/src/components/task/task-payment.js @@ -111,16 +111,16 @@ const StyledTab = withStyles({ flexDirection: 'row', alignItems: 'inherit', }, - svgIcon: { + svgIcon: { root: { width: 16, height: 16, }, - } + } })(Tab); class TaskPayment extends Component { - constructor (props) { + constructor(props) { super(props) this.state = { currentTab: 0, @@ -132,7 +132,7 @@ class TaskPayment extends Component { } } - componentDidMount () { + componentDidMount() { } @@ -167,13 +167,13 @@ class TaskPayment extends Component { return possibles[status] } - render () { + render() { const { classes, orders, offers, ...other } = this.props const TabContainer = props => { return ( - - { props.children } + + {props.children} ) } @@ -189,7 +189,7 @@ class TaskPayment extends Component { const assignTaskAndCreateOrder = async (event, offer) => { const { task, loggedUser, createOrder, assignTask, assigns } = this.props event.preventDefault() - + const assign = this.props.assigns.filter(item => item.userId === offer.userId)[0] await task.id && loggedUser.logged && await createOrder({ @@ -233,133 +233,133 @@ class TaskPayment extends Component { return ( - + - { this.props.paid && ( + {this.props.paid && ( - ) } + )}
- + } + icon={} /> } + + value={1} + label={this.props.intl.formatMessage(messages.creditCardPayment)} + icon={} /> } + + value={2} + label={this.props.intl.formatMessage(messages.payPalPayment)} + icon={} /> - - { (this.props.transferId || this.props.task?.Transfer) ? ( + + {(this.props.transferId || this.props.task?.Transfer) ? ( - - } + + } > - + {this.props.transferId ? - { `${this.props.transferId}` } + {`${this.props.transferId}`} - : + :
+ /> - +
}
) : - { orders.length > 0 ? orders.map((order, index) => ( + {orders.length > 0 ? orders.map((order, index) => (
- { order.provider === 'paypal' + {order.provider === 'paypal' ? ( - + - + - { !order.transfer_id + {!order.transfer_id ? ( - + ) : ( - - { (msg) => ( - - ) } + }} > + {(msg) => ( + + )} ) } ) : ( - + - + - - {`$ ${order.amount}`} - - - {order?.User ? 'by ' + order?.User?.name : ''} - -
} - secondary={ `${this.statuses(order.status) + ' ' + MomentComponent(order.createdAt).fromNow() || this.props.intl.formatMessage(messages.labelCreditCard)}` } + primary={ +
+ + {`$ ${order.amount}`} + + + {order?.User ? 'by ' + order?.User?.name : ''} + +
} + secondary={`${this.statuses(order.status) + ' ' + MomentComponent(order.createdAt).fromNow() || this.props.intl.formatMessage(messages.labelCreditCard)}`} /> - + ) } @@ -370,111 +370,91 @@ class TaskPayment extends Component {
- ) } - } + )} + }
- -
- { (!this.props.paid || this.props.task?.Transfer?.id) ? ( -
- { this.props.assigned ? - : null - } - { this.props?.assigns?.length > 0 ? -
- - - - await this.props.assignTask(this.props.id, id)} - onReject={async (id) => await this.props.actionAssign(this.props.id, id, false)} - /> -
: null - } - { offers?.length ? -
- - - - openMessageDialog(id, 'offers') } - onAccept={(event, offer) => confirmAssignTaskAndCreateOrder(event, offer)} - onReject={(event, offer) => onReject(event, offer)} - /> - this.setState({ confirmOrderDialog: false })} - onConfirm={(event) => assignTaskAndCreateOrder(event, this.state.currentOffer)} - offer={this.state.currentOffer} - /> -
: null - } - -
- ) : ( -
- -
- ) } -
- + +
+ {(!this.props.paid || this.props.task?.Transfer?.id) ? ( +
+ {this.props.assigned ? + : null + } + {this.props?.assigns?.length > 0 ? +
+ + + + await this.props.assignTask(this.props.id, id)} + onReject={async (id) => await this.props.actionAssign(this.props.id, id, false)} + /> +
: null + } + +
+ ) : ( +
+ +
+ )} +
+ - { hasOrders() ? ( + {hasOrders() ? (
- { !this.props.paid && ( + {!this.props.paid && ( - ) } + )}
- ) : null } - { !this.props.paid ? ( + ) : null} + {!this.props.paid ? ( ) : ( - ) } + )}
) diff --git a/frontend/src/components/task/task.js b/frontend/src/components/task/task.js index befba26b..0ec01d02 100644 --- a/frontend/src/components/task/task.js +++ b/frontend/src/components/task/task.js @@ -59,6 +59,7 @@ import TaskPaymentForm from './task-payment-form' import TaskPayments from './task-payments' import TaskLevelSplitButton from './task-level-split-button' import TaskDeadlineForm from './task-deadline-form' +import TaskOfferDrawer from './offers/task-offer-drawer' import TaskStatusIcons from './task-status-icons' @@ -1180,72 +1181,16 @@ class Task extends Component { user={this.props.user} id={task.data.id} /> - } - introTitle={ - - } - introMessage={ - - {(msg) => ( - - {msg} - - )} - - } - pickupTagListTitle={ - - - - } - pickutTagListDescription={ - - - - } - simpleInfoText={ - - {(msg) => ( - - {msg} - - )} - - } - commentAreaPlaceholder={ - - } - introImage={taskCover} + , - onClick: this.handleAssignFundingDialogClose - }, - { - label: , - onClick: this.handleOfferTask, - variant: 'contained', - color: 'secondary', - disabled: !this.state.confirmOffer || !this.state.termsAgreed || !this.state.currentPrice || this.state.currentPrice === 0 - } - ] - } - onDeliveryDateChange={(date) => this.setState({ interestedSuggestedDate: date })} - onChangePrice={(price) => this.setState({ currentPrice: price })} - onLearnCheckboxChange={(checked) => this.setState({ interestedLearn: checked })} - onTermsCheckboxChange={(checked) => this.setState({ termsAgreed: checked })} - onConfirmOfferChange={(checked) => this.setState({ confirmOffer: checked })} - onCommentChange={(e) => this.setState({ interestedComment: e.target.value })} - tabs={true} - offersProps={{ - offers: task.data.Offers - }} + offerUpdate={this.props.offerUpdate} + loggedUser={this.props.logged} + createOrder={this.props.createOrder} + assignTask={this.props.assignTask} + assigns={task.data.Assigns} + onMessage={this.props.messageOffer} /> Date: Sun, 24 Nov 2024 20:00:45 +0100 Subject: [PATCH 3/3] getting offers accepting and viewing --- .../molecules/offers-list/offers-list.tsx | 13 +++++++- .../templates/offer-drawer/offer-drawer.tsx | 2 +- .../task/offers/task-offer-drawer.tsx | 32 ++++++++++++++----- frontend/src/components/task/task.js | 3 +- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx b/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx index ef9b0d77..3b9270a9 100644 --- a/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx +++ b/frontend/src/components/design-library/molecules/offers-list/offers-list.tsx @@ -20,10 +20,18 @@ interface OfferListProps { assigned?: boolean; onAccept?: any; onReject?: any; + viewMode?: boolean; } -export default function OffersList({ offers, onMessage, assigned, onAccept, onReject }:OfferListProps) { +export default function OffersList({ + offers, + onMessage, + assigned, + onAccept, + onReject, + viewMode +}:OfferListProps) { const onSendMessage = (id) => { onMessage(id); } @@ -84,6 +92,8 @@ export default function OffersList({ offers, onMessage, assigned, onAccept, onRe } + + { !viewMode ? (
+ ) : null } } /> diff --git a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx index 3f72df42..a2e5e294 100644 --- a/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx +++ b/frontend/src/components/design-library/templates/offer-drawer/offer-drawer.tsx @@ -71,7 +71,7 @@ const OfferDrawer = ({ offersProps }: OfferDrawerProps) => { const [ currentPrice, setCurrentPrice ] = React.useState(0); - const [ enableActions, setEnableActions ] = React.useState(false); + const [ enableActions, setEnableActions ] = React.useState(true); const classes = useStyles(); diff --git a/frontend/src/components/task/offers/task-offer-drawer.tsx b/frontend/src/components/task/offers/task-offer-drawer.tsx index c2e9060e..e320c871 100644 --- a/frontend/src/components/task/offers/task-offer-drawer.tsx +++ b/frontend/src/components/task/offers/task-offer-drawer.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { FormattedMessage } from 'react-intl'; import OfferDrawer, { type OfferDrawerProps } from '../../design-library/templates/offer-drawer/offer-drawer'; import { makeStyles, Typography, } from '@material-ui/core'; @@ -19,7 +19,7 @@ type TaskOfferDrawerProps = { onClose: any; onMessage: any; assigned: boolean; - handleOfferTask: any; + updateTask: any; offerUpdate: any; loggedUser: any; createOrder: any; @@ -33,7 +33,7 @@ const TaskOfferDrawer = ({ onClose, onMessage, assigned, - handleOfferTask, + updateTask, offerUpdate, loggedUser, createOrder, @@ -44,6 +44,9 @@ const TaskOfferDrawer = ({ const classes = useStyles(); const { data } = issue + const allOffers = data?.Offers || [] + const userOffers = allOffers.filter(offer => offer.User.id === loggedUser?.user?.id) || [] + const isOwner = data?.User?.id === loggedUser?.user?.id const [interestedSuggestedDate, setInterestedSuggestedDate] = React.useState(null); const [currentPrice, setCurrentPrice] = React.useState(null); @@ -97,7 +100,19 @@ const TaskOfferDrawer = ({ setInterested(id) } - const userOffers = data?.Offers?.filter(offer => offer.User.id === loggedUser?.user?.id) || [] + const handleOfferTask = () => { + updateTask({ + id: data.id, + Offer: { + userId: loggedUser?.user?.id, + suggestedDate: interestedSuggestedDate, + value: currentPrice, + learn: interestedLearn, + comment: interestedComment + } + }) + onClose() + } return ( <> @@ -166,7 +181,7 @@ const TaskOfferDrawer = ({ onClick: handleOfferTask, variant: 'contained', color: 'secondary', - disabled: confirmOffer || termsAgreed || currentPrice || currentPrice === 0 + disabled: !confirmOffer || !termsAgreed || !currentPrice || currentPrice === 0 } ] } @@ -176,13 +191,14 @@ const TaskOfferDrawer = ({ onTermsCheckboxChange={(checked) => setTermsAgreed(checked)} onConfirmOfferChange={(checked) => setConfirmOffer(checked)} onCommentChange={(e) => setInterestedComment(e.target.value)} - tabs={!!userOffers.length} + tabs={isOwner ? !!allOffers.length : !!userOffers.length} offersProps={{ - offers: userOffers, + offers: isOwner ? allOffers : userOffers, onMessage: (id) => openMessageDialog(id), assigned: assigned, onAccept: (event, offer) => confirmAssignTaskAndCreateOrder(event, offer), - onReject: (event, offer) => onReject(event, offer) + onReject: (event, offer) => onReject(event, offer), + viewMode: data?.User?.id !== loggedUser?.user?.id }} /> diff --git a/frontend/src/components/task/task.js b/frontend/src/components/task/task.js index 0ec01d02..97de15c8 100644 --- a/frontend/src/components/task/task.js +++ b/frontend/src/components/task/task.js @@ -752,8 +752,6 @@ class Task extends Component { - -