diff --git a/src/actions/statistics.js b/src/actions/statistics.js index ce42a10bbfc018c5f3b322ff9fe70c7c7a394e7c..ce574c26e099bad3df53766b86381527f2528699 100644 --- a/src/actions/statistics.js +++ b/src/actions/statistics.js @@ -10,6 +10,8 @@ import { GET_PROFILES, GET_SELECTED_PROFILE, SET_STATUS, + ABSENT_CHANGE, + CHANGE_NO, } from './types'; export const getStaffEvents = () => ( @@ -68,14 +70,22 @@ export const getTrainees = () => ( } ); -export const visitorChange = ({ id }) => { - return (dispatch => (dispatch({ type: VISITOR_CHANGE, payload: id }))); +export const visitorChange = ({ id, value }) => { + switch (value){ + case 'Visitor': + return (dispatch => (dispatch({ type: VISITOR_CHANGE, payload: id }))); + case 'Absent': + return (dispatch => (dispatch({ type: ABSENT_CHANGE, payload: id }))); + case 'No': + return (dispatch => (dispatch({ type: CHANGE_NO, payload: id }))); + default: + } }; export const submitVisitors = ({ id, visitors }) => ( async () => { try { - const response = await axios.patch(`/api/v1/events/${id}/`, { + const response = await axios.patch(`/api/v1/staff_events/${id}/`, { visitors }); } catch (e) { @@ -97,12 +107,14 @@ export const eventDate = (name, value) => ( } ); -export const addEvent = ({ name, date }) => ( +export const addEvent = ({ name, date, description }) => ( async (dispatch) => { try { const response = await axios.post('/api/v1/staff_events/', { name, date, + description, + absent: [], }); if (response.data.id) { alert('Sikeres mentĂŠs!'); diff --git a/src/actions/types.js b/src/actions/types.js index 70b3b996856e90c25d81f5711eb40309ddda009a..71b72261ef174861f0c17c949eae701efa1655c3 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -16,6 +16,8 @@ export const GET_EVENT_BY_ID = 'get_event_by_id'; export const GET_TRAINEES = 'get_trainees'; export const VISITOR_CHANGE = 'visitor_change'; +export const ABSENT_CHANGE = 'absent_change'; +export const CHANGE_NO = 'change_no'; export const GET_NOTES_BY_EVENT = 'get_notes_by_event'; export const WRITE_EVENT = 'write_event'; diff --git a/src/components/Header.js b/src/components/Header.js index f1413a412c25404e53d4c61042661a3881031890..a8ee7e3ae3a1ad2f9154b1b6748d388ca2b36167 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -47,6 +47,7 @@ const menuItems = [ text: 'JelentkezĂŠsek', to: '/applications', prefix: '', + permissionLevel: 3, }, ] diff --git a/src/components/forms/AddEventForm.js b/src/components/forms/AddEventForm.js index af8c4b12e8b0d88922a815fb5884b66077178e65..a9dd5d98df4a8e3e717b8ef2003caddc05a3fd46 100644 --- a/src/components/forms/AddEventForm.js +++ b/src/components/forms/AddEventForm.js @@ -3,6 +3,7 @@ import { Modal, Button, Form, Input, TextArea, Icon } from 'semantic-ui-react'; import { connect } from 'react-redux'; import { DateTimeInput } from 'semantic-ui-calendar-react'; import { writeEvent, eventDate, addEvent } from '../../actions/statistics' +import { clearWrite } from '../../actions/news' class AddEventForm extends Component { constructor(props) { @@ -24,7 +25,7 @@ class AddEventForm extends Component { } render() { - const { name, date } = this.props.newEvent; + const { name, date, description } = this.props.newEvent; return ( <Modal open={this.state.showModal} @@ -39,7 +40,7 @@ class AddEventForm extends Component { <Modal.Header>Ăj alkalom:</Modal.Header> <Modal.Content style={{ - paddingTop: '50px', + paddingTop: '20px', }} > <Form> @@ -50,10 +51,17 @@ class AddEventForm extends Component { onChange={e => this.props.writeEvent(e)} value={name} style={{ - marginBottom: '50px', + marginBottom: '20px', }} placeholder='Title' /> + <Form.TextArea + name='description' + label='LeĂrĂĄs:' + placeholder='RĂśvid leĂrĂĄs' + value={description} + onChange={e => this.props.writeEvent(e)} + /> <DateTimeInput name="date" label="DĂĄtum:" @@ -69,7 +77,8 @@ class AddEventForm extends Component { <Button inverted color='red' - onClick={() => { this.setState({ showModal: false }); }} + onClick={() => { this.setState({ showModal: false }); + this.props.clearWrite();}} > <Icon name='remove' /> Cancel @@ -92,4 +101,4 @@ class AddEventForm extends Component { const mapStateToProps = ({ events: { newEvent } }) => ({ newEvent }); -export default connect(mapStateToProps, { writeEvent, addEvent, eventDate })(AddEventForm); +export default connect(mapStateToProps, { writeEvent, addEvent, eventDate, clearWrite })(AddEventForm); diff --git a/src/components/pages/EventDetail.js b/src/components/pages/EventDetail.js index dc2dffe01bcb2f1342b282afbb640e472644f5f0..e48fe9bffbeb815014d6804003e6ab4f53ca0976 100644 --- a/src/components/pages/EventDetail.js +++ b/src/components/pages/EventDetail.js @@ -10,11 +10,14 @@ import { Icon, Checkbox, Popup, + Grid, } from 'semantic-ui-react'; import { connect } from 'react-redux'; import moment from 'moment'; import { getEventById, getTrainees, visitorChange, submitVisitors } from '../../actions/statistics'; import { getNotesByEvent, writeNote, clearWrite, postEventNote } from '../../actions/notes'; +import TraineeTableRow from './TraineeTableRow'; + class EventDetail extends Component { constructor(props) { @@ -32,61 +35,31 @@ class EventDetail extends Component { renderTrainees() { + const event = this.props.selectedEvent; + const note = this.props.actualNote; return this.props.trainees.map((item) => { - const isVisitor = this.props.selectedEvent.visitors.includes(item.id); + const notes = this.props.eventNotes.filter(note => note.profile === item.id); return ( - <Table.Row> - <Table.Cell> - {item.full_name} - </Table.Cell> - {!this.state.edit ? - <Table.Cell textAlign='center'> - { - isVisitor ? - <Icon color='green' name='checkmark' /> - : - <Icon color='red' name='cancel' /> - } - </Table.Cell> - : - <Table.Cell textAlign='center'> - <Checkbox - defaultChecked={isVisitor ? true : false} - onChange={() => this.props.visitorChange(item)} - /> - </Table.Cell> - } - <Table.Cell> - <Popup - trigger={<Button icon='add' />} - content={this.props.eventNotes.map((note) => { - if (note.profile === item.id) { - return ( - <Comment.Content> - <Comment.Author>{note.created_by_name}</Comment.Author> - <Comment.Text> - {note.note} - </Comment.Text> - </Comment.Content> - ); - } - return (''); - }) - } - basic - /> - </Table.Cell> - </Table.Row> + <TraineeTableRow + selectedEvent={event} + notes={notes} + trainee={item} + edit={this.state.edit} + /> ); }); } renderEvent() { - const { name, date } = this.props.selectedEvent; + const { name, date, description } = this.props.selectedEvent; return ( <Item> <Item.Header as='h2'>{name}</Item.Header> <Item.Header as='h3'>DĂĄtum: {moment(date).format('LL')}</Item.Header> + <Container textAlign='justified'> + <Item.Header as='h3'>LeĂrĂĄs</Item.Header> + <Item.Content>{description}</Item.Content> + </Container> </Item> ); } @@ -116,7 +89,11 @@ class EventDetail extends Component { const event = this.props.selectedEvent; const note = this.props.actualNote; return ( - <Container> + <Container + style={{ + padding: '80px' + }} + > <Container textAlign='center'> { this.props.selectedEvent && this.props.trainees ? this.renderEvent() @@ -124,11 +101,6 @@ class EventDetail extends Component { '' } </Container> - <Container - style={{ - padding: '80px', - }} - > <Table celled centered> <Table.Header> <Table.Row> @@ -190,7 +162,6 @@ class EventDetail extends Component { /> </Form> </Comment.Group> - </Container> </Container> ); } diff --git a/src/components/pages/TraineeTableRow.js b/src/components/pages/TraineeTableRow.js new file mode 100644 index 0000000000000000000000000000000000000000..3a9ae4fb2e1e478c5f3b550bafc29694eff1377a --- /dev/null +++ b/src/components/pages/TraineeTableRow.js @@ -0,0 +1,150 @@ +import React, { Component } from 'react'; +import { + Comment, + Table, + Icon, + Popup, + Grid, + Button, + Form, + Dropdown, +} from 'semantic-ui-react'; +import { connect } from 'react-redux'; +import { visitorChange, submitVisitors } from '../../actions/statistics'; +import { writeNote, clearWrite, postEventNote } from '../../actions/notes'; + +const visitStates = [ + { + text: 'Igen', + value: 'Visitor', + }, + { + text: 'SzĂłlt h nem', + value: 'Absent', + }, + { + text: 'Nem', + value: 'No', + } +] + +class TraineeTableRow extends Component { + constructor(props) { + super(props); + this.state = { + showAddPopup: false, + showMorePopup: false, + }; + } + + triggerAdd = () => this.setState({ ...this.state, showAddPopup: !this.state.showAddPopup}) + triggerMore = () => this.setState({ ...this.state, showMorePopup: !this.state.showMorePopup }) + + render() { + const note = this.props.actualNote; + const { trainee, edit, actualNote, selectedEvent, notes } = this.props; + const isVisitor = selectedEvent.visitors.includes(trainee.id); + const isAbsent = selectedEvent.absent.includes(trainee.id); + return ( + <Table.Row> + <Table.Cell> + {trainee.full_name} + </Table.Cell> + {!this.props.edit ? + <Table.Cell textAlign='center'> + { + isVisitor ? + <Icon color='green' name='checkmark' /> + : + isAbsent ? + <Icon color='orange' name='minus' /> + : + <Icon color='red' name='cancel' /> + } + </Table.Cell> + : + <Table.Cell textAlign='center'> + <Dropdown + defaultValue={isVisitor ? 'Visitor' : isAbsent ? 'Absent' : 'No'} + selection + options={visitStates} + onChange={(_, v) => this.props.visitorChange({ id : trainee.id, value: v.value })} + /> + </Table.Cell> + } + <Table.Cell> + <Grid> + <Grid.Row> + <Grid.Column floated='left' width={8} textAlign='left'> + + {notes.length > 0 ? + <Comment> + <Comment.Content> + <Comment.Author>{notes[0].created_by_name}</Comment.Author> + <Comment.Text> + {notes[0].note.length > 50 ? notes[0].note.slice(0, 50).concat('...') + : + notes[0].note } + </Comment.Text> + </Comment.Content> + </Comment> + : + null + } + </Grid.Column> + <Grid.Column floated='right' width={3} textAlign='right'> + {notes.length > 0 ? + <Popup + basic + open={this.state.showMorePopup} + trigger={<Button icon='comment alternate outline' onClick={this.triggerMore} />} + content={notes.map((note) => { + return ( + <Comment.Content> + <Comment.Author>{note.created_by_name}</Comment.Author> + <Comment.Text> + {note.note} + </Comment.Text> + </Comment.Content> + ); + })} + /> + : + null} + <Popup + trigger={<Button icon='plus' onClick={this.triggerAdd}/>} + basic + open={this.state.showAddPopup} + content={ + <Form reply> + <Form.TextArea + value={note.note} + onChange={e => this.props.writeNote(e)} + /> + <Button + onClick={() => { + this.props.postEventNote({ eventid:selectedEvent.id, + userid: trainee.id, + note: note.note }); + this.props.clearWrite(); + } + } + content='MegjegyzĂŠs hozzĂĄadĂĄsa' + labelPosition='left' + icon='edit' + primary + /> + </Form> + } + /> + </Grid.Column> + </Grid.Row> + </Grid> + </Table.Cell> + </Table.Row> + ); + } +} +const mapStateToProps = ({ notes: { actualNote } }) => ({ actualNote }) + +export default connect(mapStateToProps, { writeNote, clearWrite, postEventNote, visitorChange})(TraineeTableRow) diff --git a/src/reducers/EventReducer.js b/src/reducers/EventReducer.js index 071ede590c9dae1997cfc73c2b5a49a98ccc2c94..5dd067d018da28027a91239edfb17d9b7a41637c 100644 --- a/src/reducers/EventReducer.js +++ b/src/reducers/EventReducer.js @@ -5,6 +5,9 @@ import { WRITE_EVENT, ADD_EVENT, DELETE_EVENT, + CLEAR_WRITE, + ABSENT_CHANGE, + CHANGE_NO, } from '../actions/types'; const INITIAL_STATE = { events: [], newEvent: {} }; @@ -16,16 +19,13 @@ export default (state = INITIAL_STATE, action) => { case GET_EVENT_BY_ID: return { ...state, selectedEvent: action.payload }; case VISITOR_CHANGE: - const index = state.selectedEvent.visitors.indexOf(action.payload); - if (index !== -1) { - state.selectedEvent.visitors.splice(index, 1); - return { - ...state, - selectedEvent: { - ...state.selectedEvent, - visitors: state.selectedEvent.visitors, - }, - }; + if (state.selectedEvent.visitors.includes(action.payload)) { + // Benne van nem kell megvĂĄltoztatni + return { ...state } + } + if (state.selectedEvent.absent.indexOf(action.payload) > -1) { + // Ha az absentbe van ki kell venni + state.selectedEvent.absent.splice(state.selectedEvent.absent.indexOf(action.payload), 1); } state.selectedEvent.visitors.push(action.payload) return { @@ -33,6 +33,39 @@ export default (state = INITIAL_STATE, action) => { selectedEvent: { ...state.selectedEvent, visitors: state.selectedEvent.visitors, + absent: state.selectedEvent.absent, + }, + }; + case ABSENT_CHANGE: + if (state.selectedEvent.absent.includes(action.payload)) { + return { ...state }; + } + if (state.selectedEvent.visitors.indexOf(action.payload) > -1) { + state.selectedEvent.visitors.splice(state.selectedEvent.visitors.indexOf(action.payload), 1); + } + state.selectedEvent.absent.push(action.payload); + return { + ...state, + selectedEvent: { + ...state.selectedEvent, + visitors: state.selectedEvent.visitors, + absent: state.selectedEvent.absent, + }, + }; + case CHANGE_NO: + if (state.selectedEvent.visitors.indexOf(action.payload) > -1) { + state.selectedEvent.visitors.splice(state.selectedEvent.visitors.indexOf(action.payload), 1); + } + if (state.selectedEvent.absent.indexOf(action.payload) > -1) { + // Ha az absentbe van ki kell venni + state.selectedEvent.absent.splice(state.selectedEvent.absent.indexOf(action.payload), 1); + } + return { + ...state, + selectedEvent: { + ...state.selectedEvent, + visitors: state.selectedEvent.visitors, + absent: state.selectedEvent.absent, }, }; case WRITE_EVENT: @@ -42,6 +75,8 @@ export default (state = INITIAL_STATE, action) => { case DELETE_EVENT: state.events.splice(state.events.indexOf(action.payload), 1); return { ...state, events: [...state.events] }; + case CLEAR_WRITE: + return { ...state, newEvent: {} }; default: return state; }