Merge pull request #36 from mredigonda/master

[Max Red] - Add prefix to localStorage
This commit is contained in:
Ivan Diaz 2017-06-25 01:01:42 +02:00 committed by GitHub
commit 65d89cf2bf
22 changed files with 91 additions and 33 deletions

View File

@ -29,6 +29,7 @@ class AdminPanelMyAccount extends React.Component {
profilePic: this.props.userProfilePic, profilePic: this.props.userProfilePic,
level: this.props.userLevel * 1, level: this.props.userLevel * 1,
departments: this.props.userDepartments, departments: this.props.userDepartments,
sendEmailOnNewTicket: this.props.userSendEmailOnNewTicket,
onChange: () => this.props.dispatch(SessionActions.getUserData(null, null, true)) onChange: () => this.props.dispatch(SessionActions.getUserData(null, null, true))
}; };
} }

View File

@ -27,6 +27,7 @@ class StaffEditor extends React.Component {
level: React.PropTypes.number.isRequired, level: React.PropTypes.number.isRequired,
tickets: React.PropTypes.array.isRequired, tickets: React.PropTypes.array.isRequired,
departments: React.PropTypes.array.isRequired, departments: React.PropTypes.array.isRequired,
sendEmailOnNewTicket: React.PropTypes.bool,
onChange: React.PropTypes.func, onChange: React.PropTypes.func,
onDelete: React.PropTypes.func onDelete: React.PropTypes.func
}; };
@ -40,7 +41,8 @@ class StaffEditor extends React.Component {
level: this.props.level - 1, level: this.props.level - 1,
message: null, message: null,
loadingPicture: false, loadingPicture: false,
departments: this.getUserDepartments() departments: this.getUserDepartments(),
sendEmailOnNewTicket: this.props.sendEmailOnNewTicket
}; };
render() { render() {
@ -95,7 +97,7 @@ class StaffEditor extends React.Component {
<FormField name="rpassword" validation="REPEAT_PASSWORD" required label={i18n('REPEAT_PASSWORD')} fieldProps={{size: 'large', password: true}}/> <FormField name="rpassword" validation="REPEAT_PASSWORD" required label={i18n('REPEAT_PASSWORD')} fieldProps={{size: 'large', password: true}}/>
<SubmitButton size="medium" className="staff-editor__submit-button">{i18n('UPDATE_PASSWORD')}</SubmitButton> <SubmitButton size="medium" className="staff-editor__submit-button">{i18n('UPDATE_PASSWORD')}</SubmitButton>
</Form> </Form>
{(!this.props.myAccount) ? this.renderLevelForm() : null} {(this.props.myAccount) ? this.renderSendEmailOnNewTicketForm() : this.renderLevelForm()}
<span className="separator staff-editor__separator" /> <span className="separator staff-editor__separator" />
</div> </div>
</div> </div>
@ -137,6 +139,9 @@ class StaffEditor extends React.Component {
case 'DEPARTMENTS': case 'DEPARTMENTS':
message = 'DEPARTMENTS_UPDATED'; message = 'DEPARTMENTS_UPDATED';
break; break;
case 'EMAIL_SETTING':
message = 'EMAIL_SETTING_UPDATED';
break;
case 'FAIL': case 'FAIL':
message = 'FAILED_EDIT_STAFF'; message = 'FAILED_EDIT_STAFF';
break; break;
@ -145,6 +150,18 @@ class StaffEditor extends React.Component {
return <Message className="staff-editor__message" type={messageType}>{i18n(message)}</Message>; return <Message className="staff-editor__message" type={messageType}>{i18n(message)}</Message>;
} }
renderSendEmailOnNewTicketForm() {
return (
<div>
<span className="separator staff-editor__separator"/>
<Form className="staff-editor__update-email-setting" label={i18n('EMAIL_SETTING')} values={{sendEmailOnNewTicket: this.state.sendEmailOnNewTicket}} onChange={form => this.setState({sendEmailOnNewTicket: form.sendEmailOnNewTicket})} onSubmit={this.onSubmit.bind(this, 'EMAIL_SETTING')}>
<FormField name="sendEmailOnNewTicket" label={i18n('SEND_EMAIL_ON_NEW_TICKET')} field="checkbox" fieldProps={{size: 'large'}} />
<SubmitButton size="medium" className="staff-editor__submit-button">{i18n('UPDATE')}</SubmitButton>
</Form>
</div>
);
}
renderLevelForm() { renderLevelForm() {
return ( return (
<div> <div>
@ -273,6 +290,7 @@ class StaffEditor extends React.Component {
path: '/staff/edit', path: '/staff/edit',
data: { data: {
staffId: this.props.staffId, staffId: this.props.staffId,
sendEmailOnNewTicket: form.sendEmailOnNewTicket,
email: form.email, email: form.email,
password: form.password, password: form.password,
level: (form.level !== undefined) ? form.level + 1 : null, level: (form.level !== undefined) ? form.level + 1 : null,

View File

@ -141,10 +141,17 @@
&__update-email, &__update-email,
&__update-password, &__update-password,
&__update-level { &__update-level,
&__update-email-setting {
position: relative; position: relative;
} }
&__update-email-setting {
margin-top: 28px;
margin-bottom: 20px;
text-align: left;
}
&__departments { &__departments {
border: 1px solid $grey; border: 1px solid $grey;
padding: 20px 50px; padding: 20px 50px;

View File

@ -37,7 +37,7 @@ class CreateTicketForm extends React.Component {
departmentIndex: 0, departmentIndex: 0,
email: '', email: '',
name: '', name: '',
language: 'en' language: this.props.language
} }
}; };
@ -158,6 +158,7 @@ class CreateTicketForm extends React.Component {
export default connect((store) => { export default connect((store) => {
return { return {
language: store.config.language,
allowAttachments: store.config['allow-attachments'] allowAttachments: store.config['allow-attachments']
}; };
})(CreateTicketForm); })(CreateTicketForm);

View File

@ -134,10 +134,10 @@ class FormField extends React.Component {
if (this.props.field === 'select') { if (this.props.field === 'select') {
props.selectedIndex = this.props.value; props.selectedIndex = this.props.value;
} else {
props.value = this.props.value;
} }
props.value = this.props.value;
return props; return props;
} }

View File

@ -11,6 +11,7 @@ module.exports = [
name: 'Emilia Clarke', name: 'Emilia Clarke',
email: 'staff@opensupports.com', email: 'staff@opensupports.com',
profilePic: '', profilePic: '',
sendEmailOnNewTicket: true,
level: 3, level: 3,
staff: true, staff: true,
departments: [ departments: [

View File

@ -18,6 +18,7 @@ module.exports = [
'smtp-host': 'localhost', 'smtp-host': 'localhost',
'smtp-port': '7070', 'smtp-port': '7070',
'smtp-user': 'Wesa', 'smtp-user': 'Wesa',
'session-prefix': 'opensupports-z6ctpq2winvfhchX2_',
'maintenance-mode': false, 'maintenance-mode': false,
'allow-attachments': true, 'allow-attachments': true,
'max-size': 500, 'max-size': 500,

View File

@ -156,6 +156,7 @@ module.exports = [
name: 'Kurt Gödel', name: 'Kurt Gödel',
email: 'kurt@currycurrylady.hs', email: 'kurt@currycurrylady.hs',
verified: false, verified: false,
sendEmailOnNewTicket: true,
tickets: _.times(13).map(() => { tickets: _.times(13).map(() => {
return { return {
ticketNumber: '118551', ticketNumber: '118551',
@ -375,6 +376,7 @@ module.exports = [
data: { data: {
name: 'Haskell Curry', name: 'Haskell Curry',
email: 'haskell@lambda.com', email: 'haskell@lambda.com',
sendEmailOnNewTicket: true,
tickets: [ tickets: [
{ {
ticketNumber: '445441', ticketNumber: '445441',

View File

@ -176,6 +176,8 @@ export default {
'HOME': '家', 'HOME': '家',
'TICKET_NUMBER': '票號', 'TICKET_NUMBER': '票號',
'NEXT': '下一個', 'NEXT': '下一個',
'SEND_EMAIL_ON_NEW_TICKET': '电子邮件为每个新票',
'UPDATE': '更新',
'CHART_CREATE_TICKET': '已創建門票', 'CHART_CREATE_TICKET': '已創建門票',
'CHART_CLOSE': '門票已關閉', 'CHART_CLOSE': '門票已關閉',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Zuhause', 'HOME': 'Zuhause',
'TICKET_NUMBER': 'Ticketnummer', 'TICKET_NUMBER': 'Ticketnummer',
'NEXT': 'Nächster', 'NEXT': 'Nächster',
'SEND_EMAIL_ON_NEW_TICKET': 'Email für jedes neues Ticket',
'UPDATE': 'Aktualisierung',
'CHART_CREATE_TICKET': 'Tickets erstellt', 'CHART_CREATE_TICKET': 'Tickets erstellt',
'CHART_CLOSE': 'Tickets geschlossen', 'CHART_CLOSE': 'Tickets geschlossen',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Home', 'HOME': 'Home',
'TICKET_NUMBER': 'Ticket number', 'TICKET_NUMBER': 'Ticket number',
'NEXT': 'Next', 'NEXT': 'Next',
'SEND_EMAIL_ON_NEW_TICKET': 'Send email on new ticket',
'UPDATE': 'Update',
'CHART_CREATE_TICKET': 'Tickets created', 'CHART_CREATE_TICKET': 'Tickets created',
'CHART_CLOSE': 'Tickets closed', 'CHART_CLOSE': 'Tickets closed',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Inicio', 'HOME': 'Inicio',
'TICKET_NUMBER': 'Número de Ticket', 'TICKET_NUMBER': 'Número de Ticket',
'NEXT': 'Siguiente', 'NEXT': 'Siguiente',
'SEND_EMAIL_ON_NEW_TICKET': 'Enviar email por cada nuevo ticket',
'UPDATE': 'Actualizar',
'CHART_CREATE_TICKET': 'Tickets creados', 'CHART_CREATE_TICKET': 'Tickets creados',
'CHART_CLOSE': 'Tickets cerrados', 'CHART_CLOSE': 'Tickets cerrados',
@ -248,7 +250,7 @@ export default {
'TICKETS_DESCRIPTION': 'Envíe un ticket a través de nuestro centro de soporte y obtenga respuesta de sus dudas, sugerencias y problemas.', 'TICKETS_DESCRIPTION': 'Envíe un ticket a través de nuestro centro de soporte y obtenga respuesta de sus dudas, sugerencias y problemas.',
'ARTICLES_DESCRIPTION': 'Echa un vistazo a nuestros artículos sobre temas comunes, guías y documentación.', 'ARTICLES_DESCRIPTION': 'Echa un vistazo a nuestros artículos sobre temas comunes, guías y documentación.',
'ACCOUNT_DESCRIPTION': 'Todos sus tickets están almacenados en el perfil de su cuenta. Mantenga un registro de todos los tickets envíados a nuestro equipo de soporte.', 'ACCOUNT_DESCRIPTION': 'Todos sus tickets están almacenados en el perfil de su cuenta. Mantenga un registro de todos los tickets envíados a nuestro equipo de soporte.',
'SUPPORT_CENTER_DESCRIPTION': 'Bienvenido a nuestro centro de soporte. Puede ponerse en contacto con nosotros a través de un sistema de tickets. Sus tickets serán contestadps por nuestro personal.', 'SUPPORT_CENTER_DESCRIPTION': 'Bienvenido a nuestro centro de soporte. Puede ponerse en contacto con nosotros a través de un sistema de tickets. Sus tickets serán contestados por nuestro personal.',
'CUSTOM_RESPONSES_DESCRIPTION': 'Las respuestas personalizadas son respuestas automatizadas para problemas comunes.', 'CUSTOM_RESPONSES_DESCRIPTION': 'Las respuestas personalizadas son respuestas automatizadas para problemas comunes.',
'MY_TICKETS_DESCRIPTION': 'Aquí puedes ver los tickets que tienes asignado.', 'MY_TICKETS_DESCRIPTION': 'Aquí puedes ver los tickets que tienes asignado.',
'NEW_TICKETS_DESCRIPTION': 'Aquí puedes ver todos los tickets nuevos que no están asignados por nadie.', 'NEW_TICKETS_DESCRIPTION': 'Aquí puedes ver todos los tickets nuevos que no están asignados por nadie.',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Accueil', 'HOME': 'Accueil',
'TICKET_NUMBER': 'Numéro de ticket', 'TICKET_NUMBER': 'Numéro de ticket',
'NEXT': 'Suivant', 'NEXT': 'Suivant',
'SEND_EMAIL_ON_NEW_TICKET': 'Envoyer un e-mail pour chaque nouveau ticket',
'UPDATE': 'Mettre à jour',
'CHART_CREATE_TICKET': 'Tickets créés', 'CHART_CREATE_TICKET': 'Tickets créés',
'CHART_CLOSE': 'Tickets fermés', 'CHART_CLOSE': 'Tickets fermés',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'घर', 'HOME': 'घर',
'TICKET_NUMBER': 'टिकट नंबर', 'TICKET_NUMBER': 'टिकट नंबर',
'NEXT': 'आगामी', 'NEXT': 'आगामी',
'SEND_EMAIL_ON_NEW_TICKET': 'एक ईमेल भेजने के लिए प्रत्येक नए टिकट',
'UPDATE': 'अद्यतन',
'CHART_CREATE_TICKET': 'टिकट बनाया', 'CHART_CREATE_TICKET': 'टिकट बनाया',
'CHART_CLOSE': 'टिकट बंद कर दिया', 'CHART_CLOSE': 'टिकट बंद कर दिया',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'ホーム', 'HOME': 'ホーム',
'TICKET_NUMBER': 'チケット番号', 'TICKET_NUMBER': 'チケット番号',
'NEXT': '次', 'NEXT': '次',
'SEND_EMAIL_ON_NEW_TICKET': 'メールを送信毎に新しいチケット',
'UPDATE': '更新',
'CHART_CREATE_TICKET': '作成されたチケット', 'CHART_CREATE_TICKET': '作成されたチケット',
'CHART_CLOSE': 'チケットが閉じられました', 'CHART_CLOSE': 'チケットが閉じられました',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Casa', 'HOME': 'Casa',
'TICKET_NUMBER': 'Número do bilhete', 'TICKET_NUMBER': 'Número do bilhete',
'NEXT': 'Próximo', 'NEXT': 'Próximo',
'SEND_EMAIL_ON_NEW_TICKET': 'Enviar email para cada novo ticket',
'UPDATE': 'Actualizar',
'CHART_CREATE_TICKET': 'Ingressos criados', 'CHART_CREATE_TICKET': 'Ingressos criados',
'CHART_CLOSE': 'Ingressos fechados', 'CHART_CLOSE': 'Ingressos fechados',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Главная', 'HOME': 'Главная',
'TICKET_NUMBER': 'Номер билета', 'TICKET_NUMBER': 'Номер билета',
'NEXT': 'следующий', 'NEXT': 'следующий',
'SEND_EMAIL_ON_NEW_TICKET': 'Отправить письмо на новый билет',
'UPDATE': 'Обновить',
'CHART_CREATE_TICKET': 'Билеты создано', 'CHART_CREATE_TICKET': 'Билеты создано',
'CHART_CLOSE': ' Билеты закрыты', 'CHART_CLOSE': ' Билеты закрыты',

View File

@ -176,6 +176,8 @@ export default {
'HOME': 'Ev', 'HOME': 'Ev',
'TICKET_NUMBER': 'Bilet numarası', 'TICKET_NUMBER': 'Bilet numarası',
'NEXT': 'Sonraki', 'NEXT': 'Sonraki',
'SEND_EMAIL_ON_NEW_TICKET': 'Yeni biletle e-posta gönder',
'UPDATE': 'Güncelleştirme',
'CHART_CREATE_TICKET': 'Biletler oluşturuldu', 'CHART_CREATE_TICKET': 'Biletler oluşturuldu',
'CHART_CLOSE': 'Biletler kapandı', 'CHART_CLOSE': 'Biletler kapandı',

View File

@ -19,26 +19,26 @@ describe('sessionStore library', function () {
it('should get, set and remove items from LocalStorage', function () { it('should get, set and remove items from LocalStorage', function () {
sessionStore.getItem('SOME_KEY'); sessionStore.getItem('SOME_KEY');
expect(LocalStorageMock.getItem).to.have.been.calledWith('SOME_KEY'); expect(LocalStorageMock.getItem).to.have.been.calledWith(root + '_SOME_KEY');
sessionStore.setItem('SOME_KEY', 'SOME_VALUE'); sessionStore.setItem('SOME_KEY', 'SOME_VALUE');
expect(LocalStorageMock.setItem).to.have.been.calledWith('SOME_KEY', 'SOME_VALUE'); expect(LocalStorageMock.setItem).to.have.been.calledWith(root + '_SOME_KEY', 'SOME_VALUE');
sessionStore.removeItem('SOME_KEY'); sessionStore.removeItem('SOME_KEY');
expect(LocalStorageMock.removeItem).to.have.been.calledWith('SOME_KEY'); expect(LocalStorageMock.removeItem).to.have.been.calledWith(root + '_SOME_KEY');
}); });
it('should create session correctly', function () { it('should create session correctly', function () {
sessionStore.createSession(14, 'TOKEN'); sessionStore.createSession(14, 'TOKEN');
expect(LocalStorageMock.setItem).to.have.been.calledWith('userId', 14); expect(LocalStorageMock.setItem).to.have.been.calledWith(root + '_userId', 14);
expect(LocalStorageMock.setItem).to.have.been.calledWith('token', 'TOKEN'); expect(LocalStorageMock.setItem).to.have.been.calledWith(root + '_token', 'TOKEN');
}); });
it('should return session data', function () { it('should return session data', function () {
LocalStorageMock.getItem = function (key) { LocalStorageMock.getItem = function (key) {
if (key === 'userId') return 'USER_ID'; if (key === root + '_userId') return 'USER_ID';
if (key === 'token') return 'TOKEN'; if (key === root + '_token') return 'TOKEN';
}; };
let sessionData = sessionStore.getSessionData(); let sessionData = sessionStore.getSessionData();
@ -59,8 +59,8 @@ describe('sessionStore library', function () {
it('should clear session data if session is closed', function () { it('should clear session data if session is closed', function () {
sessionStore.closeSession(); sessionStore.closeSession();
expect(LocalStorageMock.removeItem).to.have.been.calledWith('userId'); expect(LocalStorageMock.removeItem).to.have.been.calledWith(root + '_userId');
expect(LocalStorageMock.removeItem).to.have.been.calledWith('token'); expect(LocalStorageMock.removeItem).to.have.been.calledWith(root + '_token');
}); });
it('should store remember data', function () { it('should store remember data', function () {
@ -70,26 +70,26 @@ describe('sessionStore library', function () {
expiration: 20160623 expiration: 20160623
}); });
expect(LocalStorageMock.setItem).to.have.been.calledWith('rememberData-token', 'SOME_TOKEN'); expect(LocalStorageMock.setItem).to.have.been.calledWith(root + '_rememberData-token', 'SOME_TOKEN');
expect(LocalStorageMock.setItem).to.have.been.calledWith('rememberData-userId', 12); expect(LocalStorageMock.setItem).to.have.been.calledWith(root + '_rememberData-userId', 12);
expect(LocalStorageMock.setItem).to.have.been.calledWith('rememberData-expiration', 20160623); expect(LocalStorageMock.setItem).to.have.been.calledWith(root + '_rememberData-expiration', 20160623);
}); });
it('should inform if remember expired', function () { it('should inform if remember expired', function () {
LocalStorageMock.getItem = (key) => (key === 'rememberData-expiration') ? 20160505 : null; LocalStorageMock.getItem = (key) => (key === root + '_rememberData-expiration') ? 20160505 : null;
date.getCurrentDate.returns(20160506); date.getCurrentDate.returns(20160506);
expect(sessionStore.isRememberDataExpired()).to.equal(true); expect(sessionStore.isRememberDataExpired()).to.equal(true);
LocalStorageMock.getItem = (key) => (key === 'rememberData-expiration') ? 20160505 : null; LocalStorageMock.getItem = (key) => (key === root + '_rememberData-expiration') ? 20160505 : null;
date.getCurrentDate.returns(20160503); date.getCurrentDate.returns(20160503);
expect(sessionStore.isRememberDataExpired()).to.equal(false); expect(sessionStore.isRememberDataExpired()).to.equal(false);
}); });
it('should return all remember data', function () { it('should return all remember data', function () {
LocalStorageMock.getItem = function (key) { LocalStorageMock.getItem = function (key) {
if (key === 'rememberData-userId') return 'USER_ID'; if (key === root + '_rememberData-userId') return 'USER_ID';
if (key === 'rememberData-token') return 'TOKEN'; if (key === root + '_rememberData-token') return 'TOKEN';
if (key === 'rememberData-expiration') return 'EXPIRATION'; if (key === root + '_rememberData-expiration') return 'EXPIRATION';
}; };
let rememberData = sessionStore.getRememberData(); let rememberData = sessionStore.getRememberData();
@ -103,8 +103,8 @@ describe('sessionStore library', function () {
it('should clear remember data', function () { it('should clear remember data', function () {
sessionStore.clearRememberData(); sessionStore.clearRememberData();
expect(LocalStorageMock.removeItem).to.have.been.calledWith('rememberData-userId'); expect(LocalStorageMock.removeItem).to.have.been.calledWith(root + '_rememberData-userId');
expect(LocalStorageMock.removeItem).to.have.been.calledWith('rememberData-token'); expect(LocalStorageMock.removeItem).to.have.been.calledWith(root + '_rememberData-token');
expect(LocalStorageMock.removeItem).to.have.been.calledWith('rememberData-expiration'); expect(LocalStorageMock.removeItem).to.have.been.calledWith(root + '_rememberData-expiration');
}); });
}); });

View File

@ -53,6 +53,7 @@ class SessionStore {
} }
storeConfigs(configs) { storeConfigs(configs) {
this.setItem('session-prefix', configs['session-prefix']);
this.setItem('language', configs.language); this.setItem('language', configs.language);
this.setItem('reCaptchaKey', configs.reCaptchaKey); this.setItem('reCaptchaKey', configs.reCaptchaKey);
this.setItem('departments', JSON.stringify(configs.departments)); this.setItem('departments', JSON.stringify(configs.departments));
@ -106,15 +107,15 @@ class SessionStore {
} }
getItem(key) { getItem(key) {
return this.storage.getItem(key); return this.storage.getItem(root + '_' + key);
} }
setItem(key, value) { setItem(key, value) {
return this.storage.setItem(key, (value !== undefined) ? value : ''); return this.storage.setItem(root + '_' + key, (value !== undefined) ? value : '');
} }
removeItem(key) { removeItem(key) {
this.storage.removeItem(key); this.storage.removeItem(root + '_' + key);
} }
} }

View File

@ -33,7 +33,11 @@ class ConfigReducer extends Reducer {
} }
onInitConfigs(state, payload) { onInitConfigs(state, payload) {
const currentLanguage = sessionStore.getItem('language'); let currentLanguage = sessionStore.getItem('language');
if(!_.includes(payload.data.allowedLanguages, currentLanguage)) {
currentLanguage = payload.data.language;
}
sessionStore.storeConfigs(_.extend({}, payload.data, { sessionStore.storeConfigs(_.extend({}, payload.data, {
language: currentLanguage || payload.data.language language: currentLanguage || payload.data.language

View File

@ -113,7 +113,8 @@ class SessionReducer extends Reducer {
userProfilePic: userData.profilePic, userProfilePic: userData.profilePic,
userLevel: userData.level, userLevel: userData.level,
userDepartments: userData.departments, userDepartments: userData.departments,
userTickets: userData.tickets userTickets: userData.tickets,
userSendEmailOnNewTicket: userData.sendEmailOnNewTicket
}); });
} }
@ -131,7 +132,8 @@ class SessionReducer extends Reducer {
userLevel: userData.level, userLevel: userData.level,
userDepartments: userData.departments, userDepartments: userData.departments,
userTickets: userData.tickets, userTickets: userData.tickets,
userId: userId userId: userId,
userSendEmailOnNewTicket: userData.sendEmailOnNewTicket
}); });
} }