@@ -1,73 +1,72 @@
.addEditUserPopup{
.popupContent{
display: flex;
flex-direction: column;
overflow-y: auto;
padding: 22px 0px;

padding: 16px;
.inputItemWrapper{
display: flex;
flex-direction: column;
overflow-y: auto;
flex: 1 0 auto;
padding: 8px 0;
border-bottom: 1px solid #eaeaea;

.inputItemWrapper{
display: flex;
flex: 1 0 auto;
padding: 8px 0;
border-bottom: 1px solid #eaeaea;
&:last-of-type{ border: none }

.inputDescription{
white-space: nowrap;
flex: 0 0 auto;
align-items: center;
font-size: 18px;
width: 200px;
justify-content: flex-end;
margin-right: 12px;
}
.inputDescription{
white-space: nowrap;
flex: 0 0 auto;
align-items: center;
font-size: 18px;
width: 200px;
justify-content: flex-end;
margin-right: 12px;
}

.initialsInputField{
flex: 0 1 150px;
}
.initialsInputField{
flex: 0 1 150px;
}

.hoursPerWeekInputField{
flex: 0 1 44px;
justify-content: center;
text-align: center;
}
.hoursPerWeekInputField{
flex: 0 1 44px;
justify-content: center;
text-align: center;
}

.nameInputField{
flex: 0 1 400px;
}
.nameInputField{
flex: 0 1 400px;
}

.colorsWrapper{
display:flex;
flex-wrap: wrap;
margin-left: -4px;
.colorsWrapper{
display:flex;
flex-wrap: wrap;
margin-left: -4px;

.userColor{
margin:6px;
width:36px;
height:36px;
flex: 0 0 auto;
cursor:pointer;
.userColor{
margin:6px;
width:36px;
height:36px;
flex: 0 0 auto;
cursor:pointer;

.icon{
border: none;
color: white;
}
.icon{
border: none;
color: white;
}
}
}
}

.userinputMissingText{
background-color: #ff6b5c;
height: 38px;
border-radius: 2px;
padding: 3px;
padding-left: 8px;
color: #ffffff;
margin-bottom: 0px;
justify-content: center;
align-items: center;
font-size: 16px;
margin-bottom: 22px;
}
.userinputMissingText{
background-color: #ff6b5c;
height: 38px;
border-radius: 2px;
padding: 3px;
padding-left: 8px;
color: #ffffff;
margin-bottom: 0px;
justify-content: center;
align-items: center;
font-size: 16px;
margin-bottom: 22px;
}
}
@@ -4,14 +4,14 @@ import {bindActionCreators} from 'redux';
import EditUserElement from './user';
import {addNewUser} from 'actions/index';
import {deleteUser} from 'actions/index';
import {changeVacationStatusOfUser} from 'actions/index';
import ConfirmPopup from 'components/confirmPopup'
import { openConfirmPopup, closeConfirmPopup } from 'actions'
import Dialog from 'material-ui/Dialog';
import AddEditUserPopup from './addEditUserPopup';
import ConfirmPopup from 'components/confirmPopup';
import { Toast } from 'helpers';
import './styles.css';

class EditUsers extends React.Component {
class AdminpanelUsers extends React.Component {
constructor(props) {
super(props);

@@ -21,27 +21,25 @@ class EditUsers extends React.Component {
};
}

deleteUser(user){
deleteUser = (user) => {
if( user.adminHash){
Toast.error("der Admin-User darf nicht gelöscht werden.");
return;
}
this.openDeleteUserPopup(user);
}

editUser(user){
editUser(user){ // when
this.setState({addEditUserPopup_open: true});
this.addEditUserPopup = (<AddEditUserPopup user={user} editingMode={true} close={this.closeAddEditUserPopup.bind(this)}/>) ;
this.addEditUserPopup = (<AddEditUserPopup user={user} editingMode={true} close={this.closeAddEditUserPopup}/>) ;
}

openAddEditUserPopup(){
openAddEditUserPopup(editing = false, user = null){
this.setState({addEditUserPopup_open: true});
this.addEditUserPopup = (<AddEditUserPopup close={this.closeAddEditUserPopup.bind(this)}/>) ;
this.addEditUserPopup = <AddEditUserPopup editing={editing} user={user} close={this.closeAddEditUserPopup}/>
}

closeAddEditUserPopup(){
this.setState({addEditUserPopup_open: false});
}
closeAddEditUserPopup = () => this.setState({addEditUserPopup_open: false})

openDeleteUserPopup(user) {
this.deleteUserPopup =
@@ -61,53 +59,33 @@ class EditUsers extends React.Component {
this.props.deleteUser(user.ID, this.userWasDeleted.bind(this));
}

closeDeleteUserPopup() {
this.setState({deleteUserPopup_open:false})
}

userWasDeleted() {

}

changeVacationStatusOfUser = (userID, isOnVacation) => {
this.props.changeVacationStatusOfUser(userID, isOnVacation, this.vacationStatusChanged)
}

vacationStatusChanged = (userIsInVacationNow) => {

}

render() {
return (
<div className="edit-users-content">
<fb className="newUserButtonWrapper">
<button className="icon-plus button newUserButton" onClick={this.openAddEditUserPopup.bind(this)}>
<button className="icon-plus button newUserButton" onClick={this.openAddEditUserPopup}>
neuen nutzer anlegen
</button>
</fb>
{this.props.users.map(user => (
<EditUserElement
user={user}
key={user.ID}
changeVacationStatusOfUser={this.changeVacationStatusOfUser}
deleteUser={this.deleteUser.bind(this)}
editUser={this.editUser.bind(this)}
user={user}
key={user.ID}
changeVacationStatusOfUser={this.changeVacationStatusOfUser}
deleteUser={this.deleteUser}
editUser={this.openAddEditQmWizard}
/>))
}
<Dialog className="materialDialog" open={this.state.addEditUserPopup_open} onRequestClose={this.closeAddEditUserPopup.bind(this)}>
<Dialog bodyClassName='sModal' open={this.state.addEditUserPopup_open} onRequestClose={this.closeAddEditUserPopup.bind(this)}>
{this.addEditUserPopup}
</Dialog>
<Dialog className="materialDialog" open={this.state.deleteUserPopup_open} onRequestClose={this.closeDeleteUserPopup.bind(this)}>
{this.deleteUserPopup}
</Dialog>
</div>
);
}
}

const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
changeVacationStatusOfUser,
addNewUser,
deleteUser
}, dispatch);
@@ -117,4 +95,4 @@ const mapStateToProps = (state) => {
return {users: state.data.users};
};

export default connect(mapStateToProps, mapDispatchToProps)(EditUsers);
export default connect(mapStateToProps, mapDispatchToProps)(AdminpanelUsers);

This file was deleted.

@@ -28,7 +28,7 @@ class EditUserElement extends React.Component {
'isOnVacation':this.props.user.isOnVacation})}
onClick={() => this.changeVacationStatus(this.props.user.ID, !this.props.user.isOnVacation)}
></icon>
<button className="editUserButton" onClick={() => { this.props.editUser(this.props.user) }}>bearbeiten</button>
<button className="editUserButton" onClick={() => { this.props.editUser(true, this.props.user)}}>bearbeiten</button>
<icon onClick={ () => { this.props.deleteUser(this.props.user) }} className="icon-bin delteUserButton"></icon>
</fb>
);
@@ -53,11 +53,10 @@ class Apps extends PureComponent{
<fb id="apps">
<fb className="vertical">
{user ? <UserTopbar /> : <PublicTopbar />}
{/* <Route path='/Apps/TaskManager' component={PublicTopbar} /> */}
<fb id="app">
<Route path='/Apps/TaskManager' component={TaskManager} />
<Route path='/Apps/QM/:userID' component={QmApp} />
<Route path='/Apps/Adminpanel' component={AdminPanel} />
<Route path='/Apps/TaskManager' component={TaskManager} />
<Route path='/Apps/QM/:userID' component={QmApp} />
<Route path='/Apps/Adminpanel' component={AdminPanel} />
</fb>
</fb>
<Dialog open={!!this.props.selectBranchDialog} modal={true}>
@@ -48,16 +48,21 @@ class QmApp extends PureComponent {
// -------- Add and edit qm letter
openAddEditQmWizard = (isAdding = true, qmData = null) => {
this.setState({addEditQmWizardOpen: true});
let Wizard = composeWizard([DefineContentStep, AssignUsersStep]);
let Wizard = composeWizard([DefineContentStep, AssignUsersStep], qmData)
this.addEditQmWizard = (<Wizard
onClose={this.closeAddEditQmWizard}
onStepsComplete={isAdding ? this.saveFreshQmToDB : editQm}
onStepsComplete={isAdding ? this.saveFreshQmToDB : this.saveEditedQmToDB}
/>)
}

saveFreshQmToDB = (qm) => {
createQm({...qm, creatorID: this.props.selectedUser})
this.closeAddEditQmWizard()
saveFreshQmToDB = (freshQm) => {
this.props.createQm(freshQm)
this.setState({addEditQmWizardOpen: false})
}

saveEditedQmToDB = (freshQm) => {
editQm(freshQm)
this.setState({addEditQmWizardOpen: false})
}

openDeleteQmPopup = (qm) => {
@@ -127,6 +132,7 @@ class QmApp extends PureComponent {
const mapDispatchToProps = (dispatch) => (
bindActionCreators({
setSelectedUser: (userID) => ({type: 'SET_SELECTED_USER', payload: userID}),
createQm,
openConfirmPopup,
closeConfirmPopup,
}, dispatch)
@@ -1,13 +1,9 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import moment from 'moment'
import {filterUsersByBranch, createGuid, filterUsersByGroup} from 'helpers'
import {filterUsersByBranch, filterUsersByGroup} from 'helpers'
import ChipBar from 'components/chipBar'
import SelectUsersBox from 'components/selectUsersBox'
import _ from 'lodash';
import { Toast } from 'helpers';
import {Storage} from '../../../../../firebaseInstance';
import { uploadQmFile } from 'actions'
import './styles.css';


@@ -21,57 +17,6 @@ class AssignUsersStep extends Component {
componentWillMount = () => {
this.props.setStepTitle('Mitarbeiter auswählen')
this.props.setStepCompleteChecker((qm) => !!_.keys(qm.assignedUsers).length)
this.props.setStepsCompleteListener(this.onFinish)
}

onFinish = () => {
const { filesToBeDeleted, filesToUpload } = this.props.wizMemory
const qmData = this.props.OTask

/// come back here tade - take the file prop manipulation into first step !
/// espeacially the deletion.
if (filesToBeDeleted && filesToBeDeleted.length) {
filesToBeDeleted.forEach((f) => {
const freshFiles = [...qmData.files].remove(file => file.guid === f.guid)
this.props.setOTask({files: freshFiles})
Storage.ref().child(`${window.accountID}/qm/${f.guid}/${f.name}`).delete()
})
}

if (filesToUpload && filesToUpload.length) {
let processedFilesToUpload = filesToUpload.map(f => (
{name: f.name, guid: createGuid(), uploadTime: moment().toISOString(), size: f.size}
))

// adding the files that need to be uploaded already to the qmData object
const filesFresh = [...processedFilesToUpload, ...(qmData.files || [])]
this.props.editOTask({ files: filesFresh })

let readAndUploadPromises = []
filesToUpload.forEach((f, i) => {
let fileReader = new FileReader();
let readAndUploadPromise = new Promise((resolve, reject) => {
fileReader.onloadend = () => {
const fileReaderResult = fileReader.result.split(',')[1]
uploadQmFile(fileReaderResult, processedFilesToUpload[i].guid, f.name)
.then(snapshot => {
console.log('didITT!')
console.log(snapshot)
resolve(snapshot)
}).catch(c => reject(c))
}
fileReader.readAsDataURL(f)
})
readAndUploadPromises.push(readAndUploadPromise);
})

Promise.all(readAndUploadPromises).then((snapshot) => {
// finished upload succesfully
}).catch(e => {
// maybe delte the 'files' property of the qm if shit failed ?
Toast.error(`Fehler beim hochladen der Anhänge:` + e)
})
}
}

selectUsersByGroup = (gID) => {
@@ -86,12 +31,8 @@ class AssignUsersStep extends Component {
let usersArray = filterUsersByGroup(this.props.users, i).filter(u => u.ID !== this.props.user.ID)
let usersArrayFiltered = []
let selectedBranches = (this.state.selectedBranches.length > 0) ? this.state.selectedBranches : this.props.branches.map(b => b.ID) // if non branch selected, there should be no branch filter.
for (let b of selectedBranches) {
usersArrayFiltered.push(...filterUsersByBranch(usersArray, b))
}
for (let f of usersArrayFiltered) {
selectedUsersIds[f.ID] = 1;
}
for (let b of selectedBranches) { usersArrayFiltered.push(...filterUsersByBranch(usersArray, b)) }
for (let f of usersArrayFiltered) { selectedUsersIds[f.ID] = 1 }
}
this.props.editOTask({assignedUsers: selectedUsersIds})
}
@@ -112,23 +53,23 @@ class AssignUsersStep extends Component {
let selectedUsersIds = {}
for (let i of newBras) {
let usersArray = filterUsersByBranch(this.props.users, i).filter(u => u.ID !== this.props.user.ID)
for (let f of usersArray) {
selectedUsersIds[f.ID] = 1
}
for (let f of usersArray) { selectedUsersIds[f.ID] = 1 }
}
this.props.editOTask({assignedUsers: selectedUsersIds});
}

render() {
return (
<fb className="qmAssignUsersStep">
{ this.props.branches.length > 1 &&
<fb className="chipBarBranches">
<ChipBar
chips={this.props.branches}
selectedChips={this.state.selectedBranches}
chipClicked={this.selectUsersByBranch}
/>
</fb>
}
<fb className="chipBarGroups">
<ChipBar
chips={this.props.groups}
@@ -5,11 +5,20 @@ import FontIcon from 'material-ui/FontIcon';
import TextField from 'material-ui/TextField';
import Checkbox from 'material-ui/Checkbox';
//import SButton from 'components/sButton'
import { uploadQmFile } from 'actions'
import { createGuid } from 'helpers'
import moment from 'moment'
import { Toast } from 'helpers'
import _ from 'lodash'
import 'styles/modals.css';
import './styles.css';
import { Storage } from '../../../../../firebaseInstance'
import './styles.css'

export default class DefineContentStep extends Component {
constructor(props){
super(props)

this.filesToUpload = []
}

componentWillMount = () => {
this.props.setStepTitle('Aufgabenbeschreibung')
@@ -18,29 +27,52 @@ export default class DefineContentStep extends Component {

addChosenFiles = (e, f, c) => {
e.persist()
this.props.editWizMemory({
filesToUpload: [
...(this.props.wizMemory.filesToUpload || []),
...e.target.files
]
this.filesToUpload = _.uniqBy([ ...this.filesToUpload, ...e.target.files], 'name')
this.startToUpload()
this.forceUpdate()
}

startToUpload = () => {
let readAndUploadPromises = []
this.filesToUpload.forEach((f, i) => {
const qmFile = {name: f.name, guid: createGuid(), uploadTime: moment().toISOString(), size: f.size}
let fileReader = new FileReader()
let readAndUploadPromise = new Promise((resolve, reject) => {
fileReader.onloadend = () => {
const fileReaderResult = fileReader.result.split(',')[1]

uploadQmFile(fileReaderResult, qmFile.guid, qmFile.name)
.then(snapshot => {
this.filesToUpload = this.filesToUpload.filter(file => file.name !== f.name)
this.props.editOTask({files: (this.props.OTask.files || []).concat(qmFile)})
// console.log(f)
// console.log(qmFile)
// console.log(snapshot)
resolve(snapshot)
}).catch(c => {
reject(c)
})
}
fileReader.readAsDataURL(f)
})
readAndUploadPromises.push(readAndUploadPromise);
})

Promise.all(readAndUploadPromises).then((snapshot) => {
// finished upload succesfully
}).catch(e => {
Toast.error(`Fehler beim hochladen der Anhänge:` + e)
})
}

removeFile = (f) => {
const { filesToUpload, filesToBeDeleted } = this.props.wizMemory
if (_.includes(filesToUpload, f)) {
/// if removing a element that is not yet uploaded ( when creating new QM )
this.props.editWizMemory({ filesToUpload: [...filesToUpload].remove(f) })
} else {
/// if removing a element that is already uploaded ( when editing existing QM )
this.props.editWizMemory({ filesToBeDeleted: [...filesToBeDeleted, f] })
}
removeExistingFile = (f) => {
Storage.ref().child(`${window.accountID}/qm/${f.guid}/${f.name}`).delete()
const freshFiles = this.props.OTask.files.filter(file => file.guid !== f.guid)
this.props.editOTask({files: freshFiles})
}

render() {
console.log(this.props)
const { OTask, editOTask } = this.props
const { filesToBeDeleted, filesToUpload} = this.props.wizMemory
return (
<fb className='qmDefineContentMain'>
<fb className="no-shrink">
@@ -88,27 +120,21 @@ export default class DefineContentStep extends Component {
</fb>
</fb>
<fb className="no-shrink margin-top vertical">
{OTask.files && OTask.files.filter(f => !(filesToBeDeleted && filesToBeDeleted.filter(d => d.guid===f.guid)).length ).map(f => (
<fb key={f.name + f.lastModified} className="qm-file">
{OTask.files && OTask.files.map((f, i) => (
<fb key={i} className="qm-file">
<fb className="name">{f.name}</fb>
<FlatButton
primary={true}
className="iconButton"
onClick={() => this.removeFile(f)}
onClick={() => this.removeExistingFile(f)}
icon={<FontIcon className="icon icon-close" />}
/>
</fb>
))}
{filesToUpload && filesToUpload.map(f => (
<fb key={f.name + f.lastModified} className="file notUploadedYet">
<fb className="name">{f.name}</fb>
<FlatButton
primary={true}
className="iconButton"
onClick={() => this.removeFile(f)}
icon={<FontIcon className="icon icon-close" />}
/>
</fb>
{this.filesToUpload.map((f, i) => (
<fb key={i} className="file notUploadedYet">
<fb className="name">{f.name}</fb><fb>loading...</fb>
</fb>
))}
</fb>
</fb>
@@ -19,7 +19,7 @@ export default class ReadUnreadQmPopup extends PureComponent {

componentDidMount() {
this.props.qmData.files && this.props.qmData.files.forEach(f => {
Storage.ref(`qm/${f.guid}`).child(f.name).getDownloadURL().then(url => {
Storage.ref(`${window.accountID}/qm/${f.guid}`).child(f.name).getDownloadURL().then(url => {
this.setState({downloadLinksForAttachments: [...this.state.downloadLinksForAttachments, {...f, url}]})
})
})
@@ -64,7 +64,12 @@ export default class ReadUnreadQmPopup extends PureComponent {
<fb className="rurModalBodyContent">
<p>{this.props.qmData.text}</p>
{this.props.qmData.files && this.props.qmData.files.map(f => (
<AttachmentBar file={f} key={f.name + f.uploadTime + f.size}/>
<AttachmentBar
file={f}
key={f.name + f.uploadTime + f.size}
tryToOpenPDF={this.tryToOpenPDF}
tryToDownloadFile={this.tryToDownloadFile}
/>
))}
</fb>
</SModal.Body>
@@ -39,12 +39,14 @@ class UserTopbar extends PureComponent{
<fb className="topbarButtonLabel">ANSAGEN</fb>
</fb>
</Link>
<Link to={'/Apps/Adminpanel'}>
<fb className="topbarButton topbarAdminpanelButton">
<icon className="icon icon-params no-border"></icon>
<fb className="topbarButtonLabel">EINSTELLUNGEN</fb>
</fb>
</Link>
{ user.isAdmin &&
<Link to={`/Apps/Adminpanel`}>
<fb className="topbarButton topbarAdminpanelButton">
<icon className="icon icon-params no-border"></icon>
<fb className="topbarButtonLabel">EINSTELLUNGEN</fb>
</fb>
</Link>
}
</fb>
<fb className='userInfo'>
<fb className="userName">{user.name}</fb>